- live browsing of Self object memory -

lobby traitsunixFile

CopyDowns: vector

CreatorPath: traits unixFile

4 Modules

OS variants

currentOsVariant* = traits unixFile osVariants linuxhooked up to an os variant in postFileIn
osVariants = traits unixFile osVariants
currentOsVariant: =
( | cmir. vmir |
    cmir: (reflect: traits unixFile currentOsVariant).
    vmir: (reflect: variant).
    cmir = vmir ifTrue: [^ self]. "Only need to set if different."
    cmir isEmpty ifTrue: [
        "Currently the contents is the empty object.
         We are in the process of filing in the world.
         At this stage, the transporter module cache is
         not working, so we cannot use the 'at:PutContents:' 
         method to set the os variant. Instead use frozenDefine."
        cmir frozenDefine: vmir.
    ] False: [|tufMir|
        tufMir: (reflect: traits unixFile).
        "Use frozenDefine to keep module cache clean."
        tufMir frozenDefine: (tufMir copyAt: 'currentOsVariant' 
                                PutContents: vmir).
    ].
    self)
initializeOsVariant =
( 
         ( host osName = 'sunOS'  )
    || [ ( host osName = 'macOSX' )
    || [   host osName = 'linux' ]]
      ifTrue: [ currentOsVariant: host osVariantName sendTo: osVariants ])
os = unixGlobals os

asyncIO

dataReady =
( 
    (os selectReadInto: selectVec MaxFiles: maxFiles 
      IfFail: [ error: 'dataReady: select failed'. ])
        do: [|:i| fileDescriptor = (selectVec at: i) ifTrue: [^true]].
    ^false)
selectVec = a vector
setSyncIfFail: =
( 
    fcntl: fcntls f_setfl 
     With: 0
    IfFail: [|:e| ^ failBlock value: e].
    self)

constants

inetConstants = traits unixFile inetConstants
maxFiles = 64max. number of open files
mode = traits unixFile modePermissions to give file being opened.
bsdAndSolarisSharedSocketConstants = traits unixFile bsdAndSolarisSharedSocketConstants

file naming

dirPath = ( _DirPath)
dirPath: = ( _DirPath: str asVMByteVector. self)
directorySeparator = '/'
isAbsolutePath: = ( directorySeparator = path first)
pathSeparator = ':'
temporaryFileName =
( 
    "come up with a fairly unique file name"
    '/tmp/Self_temporary_file_', (time current msec printString))
Come up with a unique temporary file name. -- Ungar, 2/20/95

generated by primitiveMaker

expand: =
( 

    expand: t0 IfFail: [|:e| ^error: 'expand: failed: ', e])
expand:IfFail: =
( 

    t0 _ExpandDir_primexpandIfFail: 

    [|:e| ('badTypeError'   isPrefixOf: e)
      ||  ['deadProxyError' isPrefixOf: e]
         ifFalse: [^fb value: e] 
            True: [
                t0 asVMByteVector _ExpandDir_primexpandIfFail: fb 
         ]])
fstat =
( 

    fstatIfFail: [|:e| ^error: 'fstat failed: ', e] )
fstatIfFail: =
( 

     _fstat_wrapperfstatResultProxy: statStructure deadCopy 
      IfFail: 

    [|:e| ('badTypeError'   isPrefixOf: e)
      ||  ['deadProxyError' isPrefixOf: e]
         ifFalse: [^fb value: e] 
            True: [
                ( reviveIfFail: [|:e| ^ fb value: e]) _fstat_wrapperfstatResultProxy: statStructure deadCopy 
                  IfFail: fb 
         ]] )
setsockoptLevel:OptName:OptVal: =
( 

    setsockoptLevel: t0 OptName: t1 OptVal: t2 IfFail: 
     [|:e| ^error: 'setsockoptLevel:OptName:OptVal: failed: ', e])
setsockoptLevel:OptName:OptVal:IfFail: =
( 

     _setsockoptLevel: t0 OptName: t1 OptVal: t2 IfFail: 

    [|:e| ('badTypeError'   isPrefixOf: e)
      ||  ['deadProxyError' isPrefixOf: e]
         ifFalse: [^fb value: e] 
            True: [
                ( reviveIfFail: [|:e| ^ fb value: e]) _setsockoptLevel: t0 asSmallInteger OptName: 
                  t1 asSmallInteger OptVal: 
                  t2 asVMByteVector IfFail: fb 
         ]])
fileDescriptor =
( 

    fileDescriptorIfFail: 
     [|:e| ^error: 'fileDescriptor failed: ', e])
fileDescriptorIfFail: =
( 

     _MYSELFfileDescriptorIfFail: 

    [|:e| ('badTypeError'   isPrefixOf: e)
      ||  ['deadProxyError' isPrefixOf: e]
         ifFalse: [^fb value: e] 
            True: [
                ( reviveIfFail: [|:e| ^ fb value: e]) _MYSELFfileDescriptorIfFail: fb 
         ]])
setFd: =
( 

    setFd: t0 IfFail: [|:e| ^error: 'setFd: failed: ', e])
setFd:IfFail: =
( 

    t0 _MYSELFsetFdResultProxy: self IfFail: 

    [|:e| ('badTypeError'   isPrefixOf: e)
      ||  ['deadProxyError' isPrefixOf: e]
         ifFalse: [^fb value: e] 
            True: [
                t0 asSmallInteger _MYSELFsetFdResultProxy: self IfFail: fb 
         ]])

opening

openTCPHost:Port:IfFail: =
( | a. addrs. s |
    addrs: (os hostAddressesForName: host IfFail: [|:err| 
        ^ errBlk value: 'hostAddressForName failed: ', err.
    ]).
    a: addrs first.    "Should perhaps be more careful here?"

    s: socketDomain: socketConstants pf_inet Type: socketConstants sock_stream Protocol: 0
       IfFail: [|:e| ^ errBlk value: 'socket failed: ', e].

    s connectFamily: socketConstants af_inet Port: port Address: a
       IfFail: [|:e|  s closeIfFail: [].   ^ errBlk value: 'connect failed: ', e].

    s)
openTCPListenerOnPort:IfFail: =
( | s |
    s: socketDomain: socketConstants pf_inet Type: socketConstants sock_stream Protocol: 0
       IfFail: [|:e| ^ errBlk value: 'socket failed: ', e].

    s bindFamily: socketConstants af_inet Port: port Address: inetConstants in_addr_any
          IfFail: [|:err|   s closeIfFail: [].  ^ errBlk value: 'bind failed: ', err].

    s listenBacklog: 5  
             IfFail: [|:e|   s closeIfFail: [].  ^ errBlk value: 'listen failed: ', e].

    s)

reading

noLockReadInto:Min:Max:At:IfFail: =
( | transferred <- 0 |
    [| res <- 0. |
        res: (os basicReadFile: self Into: buf
              Offset: start + transferred
              Count: max - transferred IfFail: [|:e|
                  ('NOERR'  != e) && ['EINTR'       != e] &&
                  ['EAGAIN' != e] && ['EWOULDBLOCK' != e] ifTrue: [
                      ^ fb value: e.  "Real error!"
                  ].
                  suspendIfAsync. "Not real error. Just retry."
                  -1.   "Note can't use 0 to indicate this case,
                         since 0 already indicates EOF."
        ]).
        -1 != res ifTrue: [
            0 = res ifTrue: [
              (transferred < min) ifTrue: [ 
                  ^ fb value: 'EOF reached before min transfer limit'
              ].
              atEOF: true. 
              ^ transferred
            ].
            transferred: transferred + res.
        ].
        transferred < min.
    ] whileTrue.
    transferred)

socket operations

accepting

acceptConnectionInfo:IfFail: =
( | err. info. newSocket |
    info: (vector copySize: 3).
    readSema protectNoNLR: [   "Don't call 'errBlk' while holding lock!"
        [|:abort. :again|
          newSocket: (os acceptSocket: self Info: info IfFail: [|:e|
               ('NOERR'       = e) || 
               ['EWOULDBLOCK' = e] ||
               ['EAGAIN'      = e] ifTrue: [suspendIfAsync. again value]
                                    False: [err: e.         abort value].
          ]).
          newSocket initialize: 'accepted connection'.
          abort value.   "Exit the loop successfully."
        ] loopExitContinue.
    ].
    err ifNotNil: [^ errBlk value: err].
    infoBlk value: (info at: 0)     "Port; an integer."
             With: (info at: 1)     "Family; an integer."
             With: (info at: 2).    "Address; a byte vector."
    newSocket)
Returns a socket. Accept returns NOERR if there is no connetion yet. Before successful return, 'infoBlk' is invoked with data about the accepted connection: the port number (an integer), the family (an integer), and the address (a byteVector).

binding

bindFamily:Port:Address:IfFail: =
( 
    [
      [ |:repeat|
        ^ os bindSocket: self
                 Family: socketConstants af_inet 
                   Port: port 
                Address: inetConstants in_addr_any
                 IfFail: [|:err|
                          case if: [err = 'EADDRNOTAVAIL'] Then: repeat
                               If: [err = 'UNKNOWN 126'      ] Then: repeat
                               If: [err = 'NOERR'      ] Then: repeat
                             Else: [ errBlk value: err ].
                 ].
      ] exit.
    ] loop)
Upon success, the bind call returns the port number (if it is specified as 0, the system will chose one for us). Agesen, june 1996.

connecting

connectFamily:Port:Address:IfFail: =
( | err. res |
    readSema protectNoNLR: [
        | again |
        [
            "Loop until we have a real error or a result."
             again: false.
             res: (os connectSocket: self Family: family 
                       Port: port Address: address IfFail: [|:e|
                  ('UNKNOWN 149' = e) || [('UNKNOWN 150' = e) ||
                 [('EINPROGRESS' = e) || [('EALREADY'    = e) ||
                 [('EAGAIN'      = e) || [('EWOULDBLOCK' = e) ||
                 [('NOERR'       = e)]]]]]] ifTrue: [
                     "Not a real error: retry after suspending." 
                     suspendIfAsync.
                     again: true.
                 ] False: [
                     ('EISCONN' = e) || ['UNKNOWN 133' = e] ifTrue: [0 "really OK"]
                                                             False: [err: e].
                 ].
             ]).
        ] untilFalse: [again].
    ].
    err ifNil:    [res]
        IfNotNil: errBlk)

writing

noLockWriteFrom:Count:Start:IfFail: =
( | transferred <- 0 |
    [| res <- 0. |
        res: (os basicWriteFile: self Into: buf
              Offset: start + transferred
               Count: count - transferred IfFail: [|:e|
                  ('EAGAIN' != e) && ['EWOULDBLOCK' != e] ifTrue: [
                      ^ fb value: e.   "Real error."
                  ].
                  suspendIfAsync.   "Not real error. Just retry."
                  0.               "Pretend nothing was written."
        ]).
        transferred: transferred + res.
        transferred < count.
    ] whileTrue.
    self)