Skip to content

Commit 78f7581

Browse files
authored
Merge pull request #18 from GemTalk/normg-issue-17
Fix various issues
2 parents 3575de4 + e9dd311 commit 78f7581

23 files changed

+815
-153
lines changed

NEWS.md

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Version 1.1, December 22, 2024
2+
3+
## GemStone version 3.7.1 or later is now required. 3.7.0 and 3.6.x are no longer supported.
4+
5+
## Issues Fixed in 1.1:
6+
7+
### issue 17: Support fork and detach semantics
8+
Add support for "execute and detach" semantics. This allows the FFI to "fork" code to run on the server and tells the gem to keep running if the client logs out and/or closes the socket.
9+
10+
### issue 16: Need smalltalk logic to call thread safe library GciTsNbLogout
11+
Add GsSession>>logoutNbNoError method to call GciTsNbLogout(). This method causes an immediate logout without waiting for a response from the gem.
12+
13+
### issue 12: Should GsSession>>logout signal an error if not logged in?
14+
This was a bug. GsSession>>logout now raises an error if the session is not logged in. To avoid the exception, use #logoutNbNoError or #logoutNoError.
15+
16+
### issue 5: SparkleFFI should trim white space on strings passed to C that are used in the NRS
17+
Remove whitespace from stone, netldi, host, logPattern, dirPattern .

README.md

+32-26
Original file line numberDiff line numberDiff line change
@@ -2,49 +2,55 @@
22
GemStone GCI access via Pharo FFI
33

44
## Prerequisites
5+
6+
### Version 1.1
7+
**GemStone version ==3.7.1== or later is now required!**
8+
9+
Tested on Pharo 9, 10, 11 on Windows and Linux. Other Pharo versions/platforms will probably work but might not.
10+
511
Installation instructions assume that you have registered SSH Keys with your GitHub account. See [Connecting to GitHub with SSH](https://help.github.com/articles/connecting-to-github-with-ssh/) for more information.
612

713
You must have git installed: [git setup](https://help.github.com/articles/set-up-git/)
814

9-
You must have access to the GemStone client libraries for 3.6.x or 3.7.0 for the client platform you're running on .
15+
You must have access to the GemStone client libraries for 3.7.1 or later for the client platform you're running on .
1016
The build step [slow|fast]clientlibs generates a zip file containing these libraries in the correct directory structure.
1117

1218
## Installation
1319

1420
If you are installing Sparkle, it will automatically install PharoGemStoneFFI, and there is no need to perform an manual install of PharoGemStoneFFI. See [Sparkle on github](https://github.com/GemTalk/Sparkle); the Installation Guide is under Documentation.
1521

1622
### Client Library Installation
17-
Choose a location for the client library files and copy the client library zip file to that location. ClientLibs for Alpha5 are available here:
18-
https://downloads.gemtalksystems.com/pub/GemStone64/3.7.0-Alpha5/GemStoneClientLibs3.7.0-x86.Windows_NT.zip
19-
https://downloads.gemtalksystems.com/pub/GemStone64/3.7.0-Alpha5/GemStoneClientLibs3.7.0-x86_64.Linux.zip
23+
Choose a location for the client library files and copy the client library zip file to that location. ClientLibs are available here:
24+
https://downloads.gemtalksystems.com/pub/GemStone64/3.7.1/GemStoneClientLibs3.7.1-x86.Windows_NT.zip
25+
https://downloads.gemtalksystems.com/pub/GemStone64/3.7.1/GemStoneClientLibs3.7.1-x86_64.Linux.zip
2026

2127
unzip the zip file into a directory named clientLibs.
2228

2329
The examples below show installing on Windows under cygwin, but the process is similar for Linux.
2430
```
2531
$ mkdir clientlibs
2632
$ cd clientlibs
27-
$ cp installdir/GemStoneClientLibs3.7.0-x86.Windows_NT.zip .
28-
$ unzip GemStoneClientLibs3.7.0-x86.Windows_NT.zip
29-
Archive: GemStoneClientLibs3.7.0-x86.Windows_NT.zip
30-
creating: 3.7.0/
31-
creating: 3.7.0/32bit/
32-
inflating: 3.7.0/32bit/libgcirpc-3.7.0-32.dll
33-
inflating: 3.7.0/32bit/libgcirpc-3.7.0-32.pdb
34-
inflating: 3.7.0/32bit/libgcits-3.7.0-32.dll
35-
inflating: 3.7.0/32bit/libgcits-3.7.0-32.pdb
36-
inflating: 3.7.0/32bit/libssl-3.7.0-32.dll
37-
inflating: 3.7.0/32bit/libssl-3.7.0-32.pdb
38-
inflating: 3.7.0/32bit/vcruntime140d.dll
39-
creating: 3.7.0/64bit/
40-
inflating: 3.7.0/64bit/libgcirpc-3.7.0-64.dll
41-
inflating: 3.7.0/64bit/libgcirpc-3.7.0-64.pdb
42-
inflating: 3.7.0/64bit/libgcits-3.7.0-64.dll
43-
inflating: 3.7.0/64bit/libgcits-3.7.0-64.pdb
44-
inflating: 3.7.0/64bit/libssl-3.7.0-64.dll
45-
inflating: 3.7.0/64bit/libssl-3.7.0-64.pdb
46-
inflating: 3.7.0/64bit/vcruntime140d.dll
47-
inflating: 3.7.0/64bit/vcruntime140_1d.dll
33+
$ cp installdir/GemStoneClientLibs3.7.1-x86.Windows_NT.zip .
34+
$ unzip GemStoneClientLibs3.7.1-x86.Windows_NT.zip
35+
Archive: GemStoneClientLibs3.7.1-x86.Windows_NT.zip
36+
creating: 3.7.1/
37+
creating: 3.7.1/32bit/
38+
inflating: 3.7.1/32bit/libgcirpc-3.7.1-32.dll
39+
inflating: 3.7.1/32bit/libgcirpc-3.7.1-32.pdb
40+
inflating: 3.7.1/32bit/libgcits-3.7.1-32.dll
41+
inflating: 3.7.1/32bit/libgcits-3.7.1-32.pdb
42+
inflating: 3.7.1/32bit/libssl-3.7.1-32.dll
43+
inflating: 3.7.1/32bit/libssl-3.7.1-32.pdb
44+
inflating: 3.7.1/32bit/vcruntime140d.dll
45+
creating: 3.7.1/64bit/
46+
inflating: 3.7.1/64bit/libgcirpc-3.7.1-64.dll
47+
inflating: 3.7.1/64bit/libgcirpc-3.7.1-64.pdb
48+
inflating: 3.7.1/64bit/libgcits-3.7.1-64.dll
49+
inflating: 3.7.1/64bit/libgcits-3.7.1-64.pdb
50+
inflating: 3.7.1/64bit/libssl-3.7.1-64.dll
51+
inflating: 3.7.1/64bit/libssl-3.7.1-64.pdb
52+
inflating: 3.7.1/64bit/vcruntime140d.dll
53+
inflating: 3.7.1/64bit/vcruntime140_1d.dll
4854
4955
```
5056
The installdir/clientLibs directory is your client libs directory. Remember this location, you will need it later.
@@ -61,7 +67,7 @@ cd <GitHub clones directory>
6167
git clone [email protected]:GemTalk/PharoGemStoneFFI.git
6268
```
6369
If you have already performed the clone, do a "git pull origin development" before running the install (if you will install the current developement branch).
64-
* Start a Pharo 9 or 10 image and open Iceberg.
70+
* Start a Pharo 11 or 12 image and open Iceberg.
6571
* In the Repositories window, click "+" and select "Import from existing clone".
6672
* Select the directory you cloned to above and add the repository.
6773
* Right click and select "Load" to load the code.

src/GemStoneFFI-Tests/GciInterfaceTest.class.st

100644100755
+4-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
Class {
22
#name : 'GciInterfaceTest',
33
#superclass : 'GemStoneFFITestCase',
4-
#category : 'GemStoneFFI-Tests'
4+
#category : 'GemStoneFFI-Tests',
5+
#package : 'GemStoneFFI-Tests'
56
}
67

78
{ #category : 'tests' }
@@ -10,9 +11,10 @@ GciInterfaceTest >> testAsLocalObject [
1011
self
1112
assert: (GciInterface asLocalObject: GciInterface oopTrue) identicalTo: true ;
1213
assert: (GciInterface asLocalObject: GciInterface oopFalse) identicalTo: false ;
14+
assert: (GciInterface asLocalObject: GciInterface oopNil) identicalTo: nil ;
1315
assert: (GciInterface oopIsSmallInt: 5330) ;
1416
deny: (GciInterface oopIsSmallInt: 5332) ;
1517
assert: (GciInterface asLocalObject: 5330) identicalTo: 666 ;
16-
assert: (GciInterface asLocalObject: GciInterface OOP_CLASS_SYMBOL) identicalTo: nil .
18+
assert: (GciInterface asLocalObject: GciInterface OOP_CLASS_SYMBOL) identicalTo: Object .
1719
^ self
1820
]

src/GemStoneFFI-Tests/GemStoneFFITestCase.class.st

100644100755
+8-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ Class {
77
'netldi',
88
'stone'
99
],
10-
#category : 'GemStoneFFI-Tests'
10+
#category : 'GemStoneFFI-Tests',
11+
#package : 'GemStoneFFI-Tests'
1112
}
1213

1314
{ #category : 'acccessing' }
@@ -31,6 +32,12 @@ GemStoneFFITestCase class >> host: hostOrIp [
3132
host := hostOrIp
3233
]
3334

35+
{ #category : 'testing' }
36+
GemStoneFFITestCase class >> isAbstract [
37+
^ self name = GemStoneFFITestCase
38+
39+
]
40+
3441
{ #category : 'acccessing' }
3542
GemStoneFFITestCase class >> netldi [
3643
^netldi

src/GemStoneFFI-Tests/GsExternalByteStringTest.class.st

100644100755
+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
Class {
22
#name : 'GsExternalByteStringTest',
33
#superclass : 'GemStoneFFITestCase',
4-
#category : 'GemStoneFFI-Tests'
4+
#category : 'GemStoneFFI-Tests',
5+
#package : 'GemStoneFFI-Tests'
56
}
67

78
{ #category : 'tests' }

src/GemStoneFFI-Tests/GsSessionTest.class.st

100644100755
+159-1
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,127 @@
11
Class {
22
#name : 'GsSessionTest',
33
#superclass : 'GemStoneFFITestCase',
4-
#category : 'GemStoneFFI-Tests'
4+
#category : 'GemStoneFFI-Tests',
5+
#package : 'GemStoneFFI-Tests'
56
}
67

8+
{ #category : 'instance creation' }
9+
GsSessionTest class >> newLoggedInSession [
10+
11+
^ self newSession loginWithGsUser: 'DataCurator' password: 'swordfish' ; keepGemLog ; yourself
12+
13+
]
14+
715
{ #category : 'instance creation' }
816
GsSessionTest class >> newSession [
917

1018
^ GsSession newForGsVersion: self gsVersion threadSafe: true stone: self stone host: self host netldi: self netldi
1119
]
1220

21+
{ #category : 'tests' }
22+
GsSessionTest >> buildStringForSessionId: id [
23+
24+
"Build a string to be executed by session 2. This code will wait for up to 60 seconds for the session with the given id to exit.
25+
It will then return the value of the shared counter, which should be 30."
26+
| ws |
27+
ws := WriteStream on: String new.
28+
ws
29+
nextPutAll: '| end delay result |' ; lf ;
30+
nextPutAll: 'end := DateTime now addSeconds: 60.' ; lf ;
31+
nextPutAll: 'delay := Delay forMilliseconds: 250.' ; lf ;
32+
nextPutAll: '[System currentSessions includesIdentical: ' ; nextPutAll: id asString ; nextPutAll: ' ] whileTrue:[' ; lf ;
33+
nextPutAll: ' DateTime now > end ifTrue:[ ^ false asString ].' ; lf ;
34+
nextPutAll: 'delay wait.' ; lf ;
35+
nextPutAll: '].' ; lf ;
36+
nextPutAll: 'result := System sharedCounter: 1.' ; lf ;
37+
nextPutAll: 'GsFile gciLogServer: (''result was '', result asString) . ' ; lf ;
38+
nextPutAll: '^ result' .
39+
^ ws contents
40+
41+
42+
]
43+
44+
{ #category : 'tests' }
45+
GsSessionTest >> doTestForkAndDetachWith: ses1 and: ses2 [
46+
47+
"Test fork and detach. session 1 is forked and increments a shared counter in the server 30 times, sleeping 500 ms
48+
after each increment. session 2 waits for session 1 to exit and verifies the counter value is 30.
49+
Test takes approx 15 seconds depending on network speed and stone loading."
50+
| ses1id ses1str ses2str r1 r2 |
51+
ses1str := '| delay |
52+
System sharedCounter: 1 setValue: 0 .
53+
delay := Delay forMilliseconds: 500.
54+
30 timesRepeat:[
55+
System sharedCounter: 1 incrementBy: 1 .
56+
delay wait
57+
].
58+
System logout' .
59+
ses1id := ses1 gemSessionId .
60+
ses2str := self buildStringForSessionId: ses1id .
61+
r1 := ses1 executeStringAndDetachNb: ses1str.
62+
ses1 logoutNbNoError .
63+
r2 := ses2 executeString: ses2str.
64+
self assert: r2 equals: 30 .
65+
^ self
66+
67+
68+
69+
]
70+
71+
{ #category : 'tests' }
72+
GsSessionTest >> testForkAndDetach [
73+
|ses1 ses2 |
74+
self timeLimit: 1 minute. "this test takes awhile"
75+
ses1 := self class newLoggedInSession .
76+
ses2 := self class newLoggedInSession .
77+
[ self doTestForkAndDetachWith: ses1 and: ses2 ]
78+
ensure:[ ses1 logoutNbNoError. ses2 logoutNbNoError ] .
79+
^ self
80+
81+
]
82+
83+
{ #category : 'tests' }
84+
GsSessionTest >> testGemLogFileContents [
85+
86+
| s |
87+
s := self class newLoggedInSession.
88+
[ | tmp | self assert: (tmp := s gemLogFileNameContents) class identicalTo: ByteString ]
89+
ensure:[ s logoutNbNoError ].
90+
^ self
91+
92+
]
93+
94+
{ #category : 'tests' }
95+
GsSessionTest >> testGemLogFileName [
96+
97+
| s |
98+
s := self class newLoggedInSession.
99+
[ | tmp | self assert: (tmp := s gemLogFileName) class identicalTo: ByteString ]
100+
ensure:[ s logoutNbNoError ].
101+
^ self
102+
103+
]
104+
105+
{ #category : 'tests' }
106+
GsSessionTest >> testGemProcessId [
107+
108+
| s |
109+
s := self class newLoggedInSession.
110+
[ | tmp | self assert: (tmp := s gemProcessId) isInteger ] ensure:[ s logoutNbNoError ].
111+
^ self
112+
113+
]
114+
115+
{ #category : 'tests' }
116+
GsSessionTest >> testGemSessionId [
117+
118+
| s |
119+
s := self class newLoggedInSession.
120+
[ | tmp | self assert: (tmp := s gemSessionId) isInteger ] ensure:[ s logoutNbNoError ].
121+
^ self
122+
123+
]
124+
13125
{ #category : 'tests' }
14126
GsSessionTest >> testGetNbCallStatus [
15127
|s r|
@@ -50,6 +162,16 @@ self assert: r equals: 'Hello, World!'.
50162
^self
51163
]
52164

165+
{ #category : 'tests' }
166+
GsSessionTest >> testKeepGemLog [
167+
168+
| s |
169+
s := self class newLoggedInSession.
170+
[ | tmp| self assert: (tmp := s keepGemLog) ] ensure:[ s logoutNbNoError ].
171+
^ self
172+
173+
]
174+
53175
{ #category : 'tests' }
54176
GsSessionTest >> testLogin [
55177

@@ -63,6 +185,42 @@ self
63185

64186
]
65187

188+
{ #category : 'tests' }
189+
GsSessionTest >> testLoginWithSpaces [
190+
191+
"Test issue 5: login with leading and trailing spaces"
192+
193+
| stn hst nldi sess |
194+
stn := ' ', self class stone, ' '.
195+
host :=
196+
hst := ' ', self class host, ' '.
197+
nldi := ' ', self class netldi, ' '.
198+
199+
sess := GsSession
200+
newForGsVersion: self class gsVersion
201+
threadSafe: true
202+
stone: stn
203+
host: hst
204+
netldi: nldi.
205+
[ self
206+
assert: sess class identicalTo: GsSession ;
207+
assert: (sess loginWithGsUser: 'DataCurator' password: 'swordfish')
208+
] ensure:[ sess ifNotNil:[ sess logoutNbNoError ] ].
209+
210+
^ self
211+
212+
]
213+
214+
{ #category : 'tests' }
215+
GsSessionTest >> testLogoutError [
216+
"test issue 12"
217+
|sess|
218+
sess := self class newSession .
219+
self should:[ sess logout ] raise: Error.
220+
^self
221+
222+
]
223+
66224
{ #category : 'tests' }
67225
GsSessionTest >> testLogoutWhenNotLoggedIn [
68226
|sess|

src/GemStoneFFI-Tests/package.st

100644100755
File mode changed.

src/GemStoneFFI/FFICalloutAPI.extension.st

-34
This file was deleted.

src/GemStoneFFI/GciErrSType.class.st

100644100755
+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ Class {
1919
#pools : [
2020
'GciTypes'
2121
],
22-
#category : 'GemStoneFFI'
22+
#category : 'GemStoneFFI',
23+
#package : 'GemStoneFFI'
2324
}
2425

2526
{ #category : 'ffi support' }

0 commit comments

Comments
 (0)