GO type embedding questions

239 views
Skip to first unread message

Andreas Otto

unread,
Nov 18, 2010, 4:45:49 AM11/18/10
to golang-nuts
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,

the following questions are open:

1. example:
package main

type first struct {
}

func (this *first) self1() {
println("*first=", this)
}

type second struct {
first
}

func (this *second) self2() {
println("*second=", this)
}

func main() {
x := new(second)
x.self1()
x.self2()
}
1. result:
*first= 0x7fc7769c7000
*second= 0x7fc7769c7000

Why are the both pointers equal ?

2.example
package main

type first struct {
}

func (this *first) self() {
println("*first=", this)
}

type second struct {
first
}

func (this *second) self() {
println("*second=", this)
}

func main() {
x := new(second)
x.self()
x.self()
}
2. result
*second= 0x7f6ea09c1000
*second= 0x7f6ea09c1000

How I call the "self" method from "first" ?

func main() {
x := new(second)
first(x).self()
x.self()
}
> test2.go:21: cannot convert x (type *second) to type *first

Why I cannot convert even if the pointers are equal ?

And the most important question:

How I can call a method of "second" from "first" without knowing
"second" in "first" ?


mfg, Andreas Otto (aotto1968)

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJM5PXNAAoJEGTcPijNG3/Aj68H/A9cLxuOQt69lJfGrpbBVx5u
8zWp0MPP4aFZXjLFRu7tHmm3s66kAU+QWJCJ8Ki3wVBheDgWMFBQOn5fA00f2LNS
C6INuL2z1s2xtmEie+6apwkQlgtAGbah1DIUehuM16Cp6s1uU3wC3ZbfgcQs8XEM
TZ5e3M1eqFIbUL6iLbi/Ht6/32h/59hv/R6+lT+RPaLpoUaRWyvNAivIDcmjF52h
rQU5CS2KnbZnp4uEcd29E/AikzeIin3yv+KMJXE9uVu89sgMuTO+uf+Dmex+hbSZ
fVLrQNus47/YYonGhR+nGLlCDqwvVNNOv+hZhW7A5/UTKgZC5De7FOhim9SLQhM=
=Y0qJ
-----END PGP SIGNATURE-----

gnu.bash

unread,
Nov 18, 2010, 5:01:18 AM11/18/10
to golang-nuts

Hi,

How I can get a function pointer of a "method"

package main

type F func()
type G func (*second) ()

type first struct {
}

func (this *first) self1() {
println("*first=", this)
}

type second struct {
first
}

func (this *second) self2() {
println("*second=", this)
}

func misc() {
println("misc")
}

func main() {
x := new(second)
y := F(misc)
z0 := F(x.self2)
z1 := G(x.self2)
x.self1()
x.self2()
y()
}

result:
test2.go:29: method x.self2 is not an expression, must be called
test2.go:29: z0 declared and not used
test2.go:30: method x.self2 is not an expression, must be called
test2.go:30: z1 declared and not used


mfg, Andreas Otto (aotto1968)

chris dollin

unread,
Nov 18, 2010, 5:17:57 AM11/18/10
to Andreas Otto, golang-nuts
On 18 November 2010 09:45, Andreas Otto <aott...@t-online.de> wrote:

> the following questions are open:
>
> 1. example:
> package main
>
> type first struct {
> }
>
> func (this *first) self1() {
>  println("*first=", this)
> }
>
> type second struct {
>  first
> }
>
> func (this *second) self2() {
>  println("*second=", this)
> }
>
> func main() {
>  x := new(second)
>  x.self1()
>  x.self2()
> }
> 1. result:
> *first= 0x7fc7769c7000
> *second= 0x7fc7769c7000
>
> Why are the both pointers equal ?

Why would they not be? The `first` field of `second` will
start at the beginning of `second` -- there's no reason I can
see that there would be padding added.

> 2.example
...


> How I call the "self" method from "first" ?

x.first.self()

> func main() {
>  x := new(second)
>  first(x).self()
>  x.self()
> }
>> test2.go:21: cannot convert x (type *second) to type *first
>
> Why I cannot convert even if the pointers are equal ?

They're of unrelated types. It doesn't matter if their underlying
address values are equal or not.

> And the most important question:
>
> How I can call a method of "second" from "first" without knowing
> "second" in "first" ?

You can't. You'll have to Make Arrangements. Which Arrangements
you make will depend on exactly what sort of effect you want.

What sort of effect do you want?

Chris

--
Chris "allusive" Dollin

chris dollin

unread,
Nov 18, 2010, 5:21:47 AM11/18/10
to gnu.bash, golang-nuts
On 18 November 2010 10:01, gnu.bash <aott...@t-online.de> wrote:
>
> How I can get a function pointer of a "method"

If T is a type which has a method named M with arguments of types
U, V, ..., (and maybe result types X, Y, ...) then

T.M

is a function with argument types T, U, V, ... (and maybe result types
X, Y ...).

[That's a meta ..., not an in-Go ...]

Andreas Otto

unread,
Nov 18, 2010, 5:31:26 AM11/18/10
to chris dollin, golang-nuts
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,

thanks for the answer...

>> And the most important question:
>>
>> How I can call a method of "second" from "first" without knowing
>> "second" in "first" ?
>
> You can't. You'll have to Make Arrangements. Which Arrangements
> you make will depend on exactly what sort of effect you want.
>
> What sort of effect do you want?
>
> Chris
>

I want to code a classical class hierarchy like in C#

using System;
using csmsgque;
namespace example {
sealed class mulserver : MqS, IServerSetup, IFactory {
MqS IFactory.Factory() {
return new mulserver();
}
public void MMUL () {
SendSTART();
SendD(ReadD() * ReadD());
SendRETURN();
}
void IServerSetup.ServerSetup() {
ServiceCreate("MMUL", MMUL);
}
static void Main(string[] argv) {
mulserver srv = new mulserver();
try {
srv.ConfigSetName("MyMulServer");
srv.LinkCreate(argv);
srv.ProcessEvent(MqS.WAIT.FOREVER);
} catch (Exception ex) {
srv.ErrorSet (ex);
}
srv.Exit();
}
}
}

The base class "MqS" has the "technology" and the
toplevel class "server" has the callbacks.

In the call above the toplevel class "server" has the
callback "MMUL" and this callback is called from code
behind the class "MqS"

The link between the callback of the toplevel class
"server" and the base class "MqS" is done using the
base class method "ServiceCreate"

in our case: ServiceCreate("MMUL", MMUL)


is this clear ?


mfg, Andreas Otto

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJM5QB9AAoJEGTcPijNG3/AW6sH/3Po/ptujjr4ciACQWS8JVi0
1hEnom7l/wOe7iTKCdTRGmKBZgjwICZ+FltGDT1JuA2tP9iNXznuD2bT/Va8jr+1
fz4KGNFn1tCWzlPVJIOMi5PU1I2onWqqvHKdwIXvTGuTZ77ivciY1//uS41tv8CX
wK3sfGcJ9xBpXf6DqS9TRhvbgxQqImH98xMiBNv4NulVlZ9KdptSSI2HdvGdLbhI
WSawB85HLs6qPqpXjY/C+igpUAelSOp/+ahBc5Dqlx34NnuguQKwoy4PQf5O0xOx
lrnexPEUNfySW4WfaBDAmjDeSIdW8lYJDd2GNyzljnRNAZ23BDt+v4/mMnfHuAE=
=ksXm
-----END PGP SIGNATURE-----

roger peppe

unread,
Nov 18, 2010, 5:35:13 AM11/18/10
to Andreas Otto, golang-nuts
On 18 November 2010 09:45, Andreas Otto <aott...@t-online.de> wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Hi,
>
> the following questions are open:
>
> 1. example:
> package main
>
> type first struct {
> }
>
> func (this *first) self1() {
>  println("*first=", this)
> }
>
> type second struct {
>  first
> }
>
> func (this *second) self2() {
>  println("*second=", this)
> }
>
> func main() {
>  x := new(second)
>  x.self1()
>  x.self2()
> }
> 1. result:
> *first= 0x7fc7769c7000
> *second= 0x7fc7769c7000
>
> Why are the both pointers equal ?

they're both equal because both structs
are at the same place in memory (although
they have different types).

it's similar to the way it works in C:

typedef struct first first;
typedef struct second second;
struct first {};
struct second {first embedded;};

void self1(first *this) {
printf("*first = %p\n", this);
}

void self2(second *this) {
printf("*second = %p\n", this);
}

void foo(void) {
second *x;
x = malloc(sizeof(second));
self1(&x->embedded);
self2(x);
}


> 2.example
> package main
>
> type first struct {
> }
>
> func (this *first) self() {
>  println("*first=", this)
> }
>
> type second struct {
>  first
> }
>
> func (this *second) self() {
>  println("*second=", this)
> }
>
> func main() {
>  x := new(second)
>  x.self()
>  x.self()
> }
> 2. result
> *second= 0x7f6ea09c1000
> *second= 0x7f6ea09c1000
>
> How I call the "self" method from "first" ?

there are two self methods. which one do you mean?

you need to understand that there is no inheritance in Go,
only embedding. first cannot be aware that it is embedded
inside second. Go is different from conventional OO
languages in this respect.

> func main() {
>  x := new(second)
>  first(x).self()
>  x.self()
> }
>> test2.go:21: cannot convert x (type *second) to type *first

i don't get that error. i get
tst.go:20: cannot convert x (type *second) to type first

which makes more sense, because first(x) is trying to
convert x to type first.

but even if you had (*first)(x).self() it would still be incorrect.

> Why I cannot convert even if the pointers are equal ?

the pointers are equal, but the types are different.
(&x.first).self() would work.

> And the most important question:
>
> How I can call a method of "second" from "first" without knowing
> "second" in "first" ?

you can't - go does not do subclassing.
if you really want first to be able to call second, then you
second must pass in the means to do so (e.g. a function pointer).

don't think subclassing - think embedding and composition.

roger peppe

unread,
Nov 18, 2010, 5:42:39 AM11/18/10
to gnu.bash, golang-nuts
On 18 November 2010 10:01, gnu.bash <aott...@t-online.de> wrote:
> How I can get a function pointer of a "method"

you'd need to create a closure.

func main() {
x := new(second)
y := F(misc)

z0 := F(func() { x.self1() })
z1 := F(func() { x.self2() })
z0()
z1()
y()
}

Andreas Otto

unread,
Nov 18, 2010, 5:46:06 AM11/18/10
to chris dollin, golang-nuts
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi, a example says more than words ....
package main

type F func()
type G func (*second) ()

type first struct {
}

func (this *first) self() {
println("*first=", this)
}

type second struct {
first
}

func (this *second) self() {
println("*second=", this)
}

func misc() {
println("misc")
}

func main() {
x := new(second)
y := F(misc)

z := G((*second).self)
x.first.self()
x.self()
y()
x.z(x)
}

result
> 6g test2.go
test2.go:29: z declared and not used
test2.go:33: x.z undefined (type second has no field or method z)

Q: How does I call a method through a function pointer reference
in our case using "z"


mfg, Andreas Otto


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJM5QPuAAoJEGTcPijNG3/A22EH/0gWPYsDlHoCcNdrGKHtH4FH
szSdKUxGlhr3xmTaM4lB15f3E14c8TfHixRg/2u1vFj1EJMRi4Y5Xm0Eo20BFZPV
+HWAD/Rk4gqm1qpXG9O1gRTUPvSVEJULO8DeJZulYuadFIstcF/oL1jJfGuYJLFr
M1GsLl33BuVSM5GmJZZS6q6nkvR3vGMsCKHK/Vecj19LNG4GnpjtXIr7oFQa5WYq
P9BzNGsRGpvLBvqg50KIMAqQOZ+D7Y7cwYa/WwV53QCYMRuuguLESSNAHyL3RIuG
tr4nTwyYUiZMROJTSLDhLqGv17Nj2an+IjX42yxU7HTalTDty0Vev752ekKbqSc=
=WLOW
-----END PGP SIGNATURE-----

Andreas Otto

unread,
Nov 18, 2010, 5:51:19 AM11/18/10
to roger peppe, golang-nuts
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,

this works

func main() {
x := new(second)
y := F(misc)

z := F(func() { x.self() })
x.first.self()
x.self()
y()
z()
}

result:

> ./test2
*first= 0x7f95c4a020f8
*second= 0x7f95c4a020f8
misc
*second= 0x7f95c4a020f8

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJM5QUnAAoJEGTcPijNG3/A0hQH/2qzvF1BvYo5UKbHYKZw+V/V
KrEL5bPR79EQS9D3H+5An9RNPaH6bVDsM4JVfq4F4px2wPa0xGecXCk4O6m3YXlU
ZEbYYhCOaf5kymQsVXdogBG1qp/1h+3IOVmZoxX9mmEgFTjt7KxHkjkMpieqXHPj
Sfg5sZwpCMF1y6p4zJDykNO/2vSCNUb8QXariHOmUwTt+jLt7hhr/9JElEAMSq1y
lxsy/dNOLmwvHUHmqEWZauxdXQIaDP+7N2Ug+8E5zaeTcMl8807RfPU7t5tkg9A0
n17y0oa+wV9f0txE76gkgKs0ALPgD2X1sBS1ngjk4NS9DXBWsw/wGQEt42HJK1Y=
=vqAy
-----END PGP SIGNATURE-----

roger peppe

unread,
Nov 18, 2010, 5:55:21 AM11/18/10
to Andreas Otto, chris dollin, golang-nuts
On 18 November 2010 10:31, Andreas Otto <aott...@t-online.de> wrote:
> I want to code a classical class hierarchy like in C#

don't!
Go does not do class hierarchies.

Andreas Otto

unread,
Nov 18, 2010, 6:04:58 AM11/18/10
to roger peppe, chris dollin, golang-nuts
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

I know, but with "embedding" and "closures"
I think I can the behavior from above


mfg, Andreas Otto
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJM5QhaAAoJEGTcPijNG3/AZv4H/3TzDy6EjWCvV2Ij5l1XOOBI
uV3m1PWVPPfTXud3Nzka2kKr9NiCOraOXOa6BkoRw667nAhVGLZ9AVGeXYw34TIh
EQnFy2UW8tI48s+eQV4hK6Wmk9w1HnAI+mz270d1GHqMDuVbNC1IZ4zt0PTCxPvM
u+2qdFC0AJ31GhcJX7nTPEjjSuLc0GHJF9/+PoMJFOX5wYMCKqykUvDuV5dlZ711
/qa8Xd0vIlNVdVCxsw895uu85Kmv1SmbW087ob3jVwjKFiamtVVxVvrDQKwcDUtJ
cnfEw3nCpV9CRci70PtmRPEk+74ySwJ1h4cLtUkx3oX4AfrDOqPzFgu0nlvalgw=
=EbHx
-----END PGP SIGNATURE-----

roger peppe

unread,
Nov 18, 2010, 6:08:33 AM11/18/10
to Andreas Otto, chris dollin, golang-nuts
On 18 November 2010 10:31, Andreas Otto <aott...@t-online.de> wrote:
> The base class "MqS" has the "technology" and the
> toplevel class "server" has the callbacks.

the classical Go way to do this kind of thing would
be to pass in an interface representing the callbacks.

but for your instance, i'm not sure that's necessary.
you could just pass in a MqS instance:

type MqS ...
func (m *MqS) SendSTART()
func (m *MqS) ReadD() int
func (m *MqS) SendD(int)
func (m *MqS) SendRETURN()

type Service struct {
*MqS
...
}

func ServiceCreate(m *MqS) *Server {
// a more conventional name might be "NewService".
return &Service{m, ...}
}
func (s *Service) MMUL() {
s.SendSTART();
s.SendD(s.ReadD() * s.ReadD());
s.SendRETURN();
}


does that start to make sense?

chris dollin

unread,
Nov 18, 2010, 6:16:08 AM11/18/10
to Andreas Otto, golang-nuts
On 18 November 2010 10:31, Andreas Otto <aott...@t-online.de> wrote:

> I want to code a classical class hierarchy like in C#

Probably not such a good move. Go deliberately doesn't support
"classical" subclassing & has other pieces of machinery for solving
the problems that subclassing is for solving.

In the example you present, I'd have the "base class", the
thing like MqS, take either a (or some) function(s), or an
object satisfying an interface, to do the superclassy thing.

Something like this:

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
package main

import "fmt"

type Base struct {
superMethod func ()
}

func (b *Base) BaseMethod() {
b.superMethod()
}

func (b *Base) Init(f func()) {
b.superMethod = f
}

type Super struct {
Base
}

func (s *Super) Init() {
s.Base.Init( func() { s.calledBack() } )
}

func (s *Super) calledBack() {
fmt.Println( "I have been called back" )
}

func main() {
var S Super
S.Init()
S.BaseMethod()
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

The "base class" Base has a function pointer for the callback
that it runs when BaseMethod is called. Here I've established
that pointer by calling an Init method -- other ways might be used.

The "superclass" Super embed a Base, which means BaseMethod
can be invoked on it. Super's Init method calls the Base init method
for this Super passing in a closure which calls calledBack on this
Super instance.

Andreas Otto

unread,
Nov 18, 2010, 6:22:23 AM11/18/10
to roger peppe, chris dollin, golang-nuts
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

looks interesting, a little bit like java ...

package example;
import javamsgque.*;
final class mulserver extends MqS implements IServerSetup, IFactory {
class MMUL implements IService {
public void Service (MqS ctx) throws MqSException {


SendSTART();
SendD(ReadD() * ReadD());
SendRETURN();
}
}

public void ServerSetup() throws MqSException {
ServiceCreate("MMUL", new MMUL());
}
public MqS Factory() {
return new mulserver();
}
public static void main(String[] argv) {
MqS.Init("java", "example.mulserver");


mulserver srv = new mulserver();
try {
srv.ConfigSetName("MyMulServer");
srv.LinkCreate(argv);
srv.ProcessEvent(MqS.WAIT.FOREVER);

} catch (Throwable e) {
srv.ErrorSet(e);
}
srv.Exit();
}
}

java need a subclass for this kind of cooding

the core problem of your example is that usually
multiple sercives are provided ...

mfg, andreas otto

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJM5QxvAAoJEGTcPijNG3/A0PoH/igxY8QKPof1UaYYEUSQ1e/G
EwlU+LkNgaLT5oUJ6wPGupzKrcfQF2/7pO11d/WmRbt2dTh68RR/gct6uzNWUknE
UXz36SKrAJyaQgy9e6x1sFxmW3ldHxQmd+sdMl2aOR5Xp6I/+CdEYeM/Jg+51CBG
tFZCdw/IARiClNf8fOilSGoZUzUV78IJcAUefi0uq/UHMDKMyFMAHzDyO4yQrtav
DeQgGnSnDtBsgHT0nYcH+inWlctlspsM60vHU5JkJN6euCjKjhnOT9ibJQQtnkOG
tkS0pdUTI+crB2meV0Jz46P0fbUbzbiz9Cd2tq+43BFHGVgUlmNTOSd8CK/Cgdk=
=B9bI
-----END PGP SIGNATURE-----

roger peppe

unread,
Nov 18, 2010, 7:29:25 AM11/18/10
to Andreas Otto, chris dollin, golang-nuts
On 18 November 2010 11:22, Andreas Otto <aott...@t-online.de> wrote:
> the core problem of your example is that usually
> multiple sercives are provided ...

in that case you need to think what all the services
have in common and define an interface that
represents that functionality.

then define your service publishing code
such that it takes that interface and does
whatever it needs with it.

go is all about *using* not *being used by*.
think active, not passive; functionality not frameworks.

Andreas Otto

unread,
Nov 19, 2010, 5:04:03 AM11/19/10
to roger peppe, chris dollin, golang-nuts
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,

I analyze this code but I have a problem.
I have one "Server" but multiple "Services"
All "Services" share "Server" local variables

1. my problem is that I have one additional level of "indirection" using
the following construct
- -> MqCallback(func() {ret.ServerSetup()})
All together I have the following Wrappers to call an arbitrary GO method

1. Wrapper in C
2. Wrapper in GO
3. func() wrapper in GO
4. finally -> method

- -> goal for now, I want to skip level "3"

for unique known Methods like "ServerSetup" I can use "interface" but
I need for "1" *and* "2" an "interface" specific code ... bad
- -> but I#ll go this way

the problem are still the services, because the method-name is user
specific

but, step by step I come closer for a solution of the services problem
- -> I'll go the JAVA way

brainstorm ..
now the result, (only the toplevel code ...)

package main

import (
. "gomsgque"
"os"
)

type Server struct {
*MqS
incr int32
}

func NewServer() *Server {
ret := &Server{NewMqS(),10}
println("NewServer...", ret)
ret.ConfigSetServerSetup(ret)
return ret
}

func (this *Server) ServerSetup() {
this.ServiceCreate("ECOI", &ECOI{this})
// ... many, many services ....
}

// Q: would like to skip the next 3 lines -> just overhead
type ECOI struct {
*Server
}

func (this *ECOI) Call() {
this.SendSTART()
// !attention! call "*Server" variable "incr"
this.SendI(this.ReadI() + this.incr)
this.SendRETURN()
}

func main() {
var srv = NewServer()
defer func() {
if x := recover(); x != nil {
srv.ErrorSet(x)
}
srv.Exit()
}()
srv.ConfigSetName("server")
srv.ConfigSetIdent("test-server")
srv.LinkCreate(os.Args...)
srv.LogC("test",1,"this is the log test\n")
srv.ProcessEvent(MqS_TIMEOUT_DEFAULT, MqS_WAIT_FOREVER)
}


and the results ... (works!!!!)

> ./client @ ./server
NewMqS... 0x71d010
C> ((null):12765:0x7f84c5dec700) [2010-11-19:10-56-40]
[0-0-0-0x71d010-client]: START
NewMqS... 0x72b010
NewServer... 0x7fecbbffd200
1. ConfigSetServerSetup ... (0x7fecbbfbf5d0,0x7fecbbffd200)
S> (server:12766:0x7fecbc0cb700) [2010-11-19:10-56-40]
[0-0-1-0x72b010-sServerSetup]: INFO
S> (server:12766:0x7fecbc0cb700) [2010-11-19:10-56-40]
[0-0-1-0x72b010-cServerSetup]: 1111111111111111111111
1. ServiceCreate ... (0x7fecbbfbf540,0x7fecbbfaa0e8)
C> (client:12765:0x7f84c5dec700) [2010-11-19:10-56-40]
[0-0-0-0x71d010-client]: SEND
S> (server:12766:0x7fecbc0cb700) [2010-11-19:10-56-40]
[0-0-3-0x72b010-sService]: INFO
S> (server:12766:0x7fecbc0cb700) [2010-11-19:10-56-40]
[0-0-3-0x72b010-cService]: 1111111111111111111111
C> (client:12765:0x7f84c5dec700) [2010-11-19:10-56-40]
[0-0-0-0x71d010-client]: READ
C> (client:12765:0x7f84c5dec700) [2010-11-19:10-56-40]
[0-0-0-0x71d010-client]: RESULT = 110
C> (client:12765:0x7f84c5dec700) [2010-11-19:10-56-40]
[0-0-0-0x71d010-client]: END
iErrorMqToGoWithCheck...
ErrorSet...


Q: how does the code look like ... OK?


mfg, Andreas Otto
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJM5kuSAAoJEGTcPijNG3/AnDsH/RW1IifwLpObysE5rlDahTZ2
o9C2K+/KQAEZQh3g7JCjZuh5U14PpYZRn2aDE5Zq58lemLm7zsqeY7aIG7LGi6Pe
u1GQvKbxUk5yir1FxSE+m5eTQxdkW7KeFf+TIPgA12kBRUz0KawJNGucKKFIHclP
km78C6GUibC4O4EQMRI8CIc6KHnLeLBYxP2pWT6F+OxRnbhW5icyssqaoa3ZE9OJ
kPFg3csU1OAHzWyZHKHl/Jo3RZWpSFoVinFS0d60iwDAJcUOgqO8C425zFGdaCFH
eOCMnflaXxWBaq0tkWx2RfjxwNV+YJ69UAoczMb5reLDlV7zzifpvd1rGj/JHQs=
=PE3m
-----END PGP SIGNATURE-----

Andreas Otto

unread,
Nov 19, 2010, 5:33:51 AM11/19/10
to roger peppe, chris dollin, golang-nuts
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,

as requested the other code as well....


/**
* \file theLink/gomsgque/src/MqS.go
* \brief \$Id: MqS.go 315 2010-11-19 10:33:21Z aotto1968 $
*
* (C) 2010 - NHI - #1 - Project - Group
*
* \version \$Rev: 315 $
* \author EMail: aotto1968 at users.berlios.de
* \attention this software has GPL permissions to copy
* please contact AUTHORS for additional information
*/

package gomsgque

/*
#include <gomsgque.h>
*/
import "C"

import (
//"fmt"
"unsafe"
//"reflect"
)

type TIMEOUT C.MQ_TIME_T
type WAIT uint32

const (
MqS_TIMEOUT_DEFAULT TIMEOUT = C.MQ_TIMEOUT_DEFAULT
MqS_TIMEOUT_USER TIMEOUT = C.MQ_TIMEOUT_USER
MqS_TIMEOUT_MAX TIMEOUT = C.MQ_TIMEOUT_MAX

MqS_WAIT_NO WAIT = C.MQ_WAIT_NO
MqS_WAIT_ONCE WAIT = C.MQ_WAIT_ONCE
MqS_WAIT_FOREVER WAIT = C.MQ_WAIT_FOREVER
)

type MqS _Ctype_struct_MqS

type MqSCallback func()

type IServerSetup interface {
ServerSetup()
}

type IServerCleanup interface {
ServerCleanup()
}

type IService interface {
Call()
}

func NewMqS() *MqS {
this := C.MqContextCreate(0,nil)
C.MqConfigSetSelf(this, unsafe.Pointer(this))
println("NewMqS...", this)
return (*MqS)(this)
}

func (this *MqS) String() string {
return C.GoString(C.MqErrorGetText((*_Ctype_struct_MqS)(this)))
}

func (this *MqS) LogC(prefix string, level int, message string) {
p := C.CString(prefix)
m := C.CString(message)
C.MqLogC((*_Ctype_struct_MqS)(this), p, C.MQ_INT(level), m)
C.free(unsafe.Pointer(m))
C.free(unsafe.Pointer(p))
}

func (this *MqS) Exit() {
C.MqExitP(C.sGO, (*_Ctype_struct_MqS)(this))
}

/**
* \file theLink/gomsgque/src/MqSException.go
* \brief \$Id: MqSException.go 314 2010-11-19 09:13:00Z aotto1968 $
*
* (C) 2010 - NHI - #1 - Project - Group
*
* \version \$Rev: 314 $
* \author EMail: aotto1968 at users.berlios.de
* \attention this software has GPL permissions to copy
* please contact AUTHORS for additional information
*/

package gomsgque

/*
#include <gomsgque.h>
*/
import "C"

import (
//"fmt"
"unsafe"
"os"
)

func (this *MqS) iErrorMqToGoWithCheck(ex uint32) {
if (ex == C.MQ_ERROR) {
println("iErrorMqToGoWithCheck...")
panic(this)
}
}

func (this *MqS) ErrorSet(ex interface{}) {
println("ErrorSet...")
if ctx,ok := ex.(*MqS); ok {
C.MqErrorCopy((*_Ctype_struct_MqS)(this), (*_Ctype_struct_MqS)(ctx))
} else if err,ok := ex.(os.Error); ok {
m := C.CString(err.String())
C.MqErrorC((*_Ctype_struct_MqS)(this), C.sGO, -1, m)
C.free(unsafe.Pointer(m))
} else {
C.MqErrorC((*_Ctype_struct_MqS)(this), C.sGO, -1, C.sUNKNOWN)
}
}

func (this *MqS) ErrorC(prefix string, level int, message string) {
p := C.CString(prefix)
m := C.CString(message)
C.MqErrorC((*_Ctype_struct_MqS)(this), p, C.MQ_INT(level), m)
C.free(unsafe.Pointer(p))
C.free(unsafe.Pointer(m))
}

func (this *MqS) ErrorSetCONTINUE() {
C.MqErrorSetCONTINUE((*_Ctype_struct_MqS)(this))
}

func (this *MqS) ErrorSetEXIT() {
r := C.MqErrorSetEXITP((*_Ctype_struct_MqS)(this),C.sGO)
this.iErrorMqToGoWithCheck(r)
}

func (this *MqS) ErrorIsEXIT() bool {
return C.MqErrorIsEXIT((*_Ctype_struct_MqS)(this)) == C.MQ_YES
}

func (this *MqS) ErrorReset() {
C.MqErrorReset((*_Ctype_struct_MqS)(this))
}

func (this *MqS) ErrorPrint() {
C.MqErrorPrint((*_Ctype_struct_MqS)(this))
}

/**
* \file theLink/gomsgque/src/MqBinary.go
* \brief \$Id: MqBinary.go 310 2010-11-17 16:21:48Z aotto1968 $
*
* (C) 2010 - NHI - #1 - Project - Group
*
* \version \$Rev: 310 $
* \author EMail: aotto1968 at users.berlios.de
* \attention this software has GPL permissions to copy
* please contact AUTHORS for additional information
*/

package gomsgque

/*
#include <gomsgque.h>
*/
import "C"

import (
//"fmt"
//"strings"
"unsafe"
)

type MqBinary struct {
D unsafe.Pointer
L int
}

func (this MqBinary) array() []byte {
byt := make([]byte, this.L)
C.memcpy(unsafe.Pointer(&byt[0]),this.D,C.size_t(this.L))
return byt
}

func (this MqBinary) string() string {
return C.GoStringN((*C.char)(this.D), C.int(this.L))
}

/**
* \file theLink/gomsgque/src/send.go
* \brief \$Id: send.go 315 2010-11-19 10:33:21Z aotto1968 $
*
* (C) 2010 - NHI - #1 - Project - Group
*
* \version \$Rev: 315 $
* \author EMail: aotto1968 at users.berlios.de
* \attention this software has GPL permissions to copy
* please contact AUTHORS for additional information
*/

package gomsgque

/*
#include <gomsgque.h>
*/
import "C"

import (
//"fmt"
//"strings"
"unsafe"
)

func (this *MqS) SendSTART() {
this.iErrorMqToGoWithCheck(C.MqSendSTART((*_Ctype_struct_MqS)(this)))
}

func (this *MqS) SendEND_AND_WAIT(token string, timeout TIMEOUT) {
t := C.CString(token)
r := C.MqSendEND_AND_WAIT((*_Ctype_struct_MqS)(this), t,
C.MQ_TIME_T(timeout))
C.free(unsafe.Pointer(t))
this.iErrorMqToGoWithCheck(r)
}

func (this *MqS) SendRETURN() {
this.iErrorMqToGoWithCheck(C.MqSendRETURN((*_Ctype_struct_MqS)(this)))
}

func (this *MqS) SendI(val int32) {
this.iErrorMqToGoWithCheck(C.MqSendI((*_Ctype_struct_MqS)(this),
C.MQ_INT(val)))
}

/**
* \file theLink/gomsgque/src/read.go
* \brief \$Id: read.go 314 2010-11-19 09:13:00Z aotto1968 $
*
* (C) 2010 - NHI - #1 - Project - Group
*
* \version \$Rev: 314 $
* \author EMail: aotto1968 at users.berlios.de
* \attention this software has GPL permissions to copy
* please contact AUTHORS for additional information
*/

package gomsgque

/*
#include <gomsgque.h>
*/
import "C"

import (
//"fmt"
//"strings"
"unsafe"
)

func (this *MqS) ReadO() bool {
tmp := C.MQ_BOL(0)
this.iErrorMqToGoWithCheck(C.MqReadO((*_Ctype_struct_MqS)(this), &tmp))
return tmp != C.MQ_BOL(0)
}

func (this *MqS) ReadY() int8 {
tmp := C.MQ_BYT(0)
this.iErrorMqToGoWithCheck(C.MqReadY((*_Ctype_struct_MqS)(this), &tmp))
return int8(tmp)
}

func (this *MqS) ReadS() int16 {
tmp := C.MQ_SRT(0)
this.iErrorMqToGoWithCheck(C.MqReadS((*_Ctype_struct_MqS)(this), &tmp))
return int16(tmp)
}

func (this *MqS) ReadI() int32 {
tmp := C.MQ_INT(0)
this.iErrorMqToGoWithCheck(C.MqReadI((*_Ctype_struct_MqS)(this), &tmp))
return int32(tmp)
}

func (this *MqS) ReadW() int64 {
tmp := C.MQ_WID(0)
this.iErrorMqToGoWithCheck(C.MqReadW((*_Ctype_struct_MqS)(this), &tmp))
return int64(tmp)
}

func (this *MqS) ReadF() float32 {
tmp := C.MQ_FLT(0.0)
this.iErrorMqToGoWithCheck(C.MqReadF((*_Ctype_struct_MqS)(this), &tmp))
return float32(tmp)
}

func (this *MqS) ReadD() float64 {
tmp := C.MQ_DBL(0.0)
this.iErrorMqToGoWithCheck(C.MqReadD((*_Ctype_struct_MqS)(this), &tmp))
return float64(tmp)
}

func (this *MqS) ReadN() MqBinary {
var tmp C.MQ_CBI
len := C.MQ_SIZE(0)
this.iErrorMqToGoWithCheck(C.MqReadN((*_Ctype_struct_MqS)(this), &tmp,
&len))
return MqBinary{unsafe.Pointer(tmp), int(len)}
}

func (this *MqS) ReadB() MqBinary {
var tmp C.MQ_BIN
len := C.MQ_SIZE(0)
this.iErrorMqToGoWithCheck(C.MqReadB((*_Ctype_struct_MqS)(this), &tmp,
&len))
return MqBinary{unsafe.Pointer(tmp), int(len)}
}

func (this *MqS) ReadU() C.MQ_BUF {
var tmp C.MQ_BUF
this.iErrorMqToGoWithCheck(C.MqReadU((*_Ctype_struct_MqS)(this), &tmp))
return tmp
}

func (this *MqS) ReadL_START(buf C.MQ_BUF) {
this.iErrorMqToGoWithCheck(C.MqReadL_START((*_Ctype_struct_MqS)(this),
buf))
}

func (this *MqS) ReadL_END() {
this.iErrorMqToGoWithCheck(C.MqReadL_END((*_Ctype_struct_MqS)(this)))
}

func (this *MqS) ReadT_START(buf C.MQ_BUF) {
this.iErrorMqToGoWithCheck(C.MqReadT_START((*_Ctype_struct_MqS)(this),
buf))
}

func (this *MqS) ReadT_END() {
this.iErrorMqToGoWithCheck(C.MqReadT_END((*_Ctype_struct_MqS)(this)))
}

func (this *MqS) ReadProxy(ctx *MqS) {
this.iErrorMqToGoWithCheck(C.MqReadProxy((*_Ctype_struct_MqS)(this),
(*_Ctype_struct_MqS)(ctx)))
}

func (this *MqS) ReadGetNumItems(ctx *MqS) uint32 {
return uint32(C.MqReadGetNumItems((*_Ctype_struct_MqS)(this)))
}


/**
* \file theLink/gomsgque/src/link.go
* \brief \$Id: link.go 314 2010-11-19 09:13:00Z aotto1968 $
*
* (C) 2010 - NHI - #1 - Project - Group
*
* \version \$Rev: 314 $
* \author EMail: aotto1968 at users.berlios.de
* \attention this software has GPL permissions to copy
* please contact AUTHORS for additional information
*/

package gomsgque

/*
#include <gomsgque.h>
*/
import "C"

import (
//"fmt"
//"strings"
"unsafe"
)

func (this *MqS) LinkCreate(argv ... string) {
var largv *_Ctype_struct_MqBufferLS
//fmt.Println("argv = " + strings.Join(argv,","))
if (len(argv) != 0) {
largv = C.MqBufferLCreate(C.MQ_SIZE(len(argv)));
for idx:= range argv {
a := C.CString(argv[idx])
C.MqBufferLAppendC(largv, a);
C.free(unsafe.Pointer(a))
}
}
this.iErrorMqToGoWithCheck(C.MqLinkCreate((*_Ctype_struct_MqS)(this),
&largv))
}


/**
* \file theLink/gomsgque/src/config.go
* \brief \$Id: config.go 315 2010-11-19 10:33:21Z aotto1968 $
*
* (C) 2010 - NHI - #1 - Project - Group
*
* \version \$Rev: 315 $
* \author EMail: aotto1968 at users.berlios.de
* \attention this software has GPL permissions to copy
* please contact AUTHORS for additional information
*/

package gomsgque

/*
#include <gomsgque.h>
*/
import "C"

import (
"fmt"
"unsafe"
)

func (this *MqS) ConfigSetName(val string) {
v := C.CString(val)
C.MqConfigSetName((*_Ctype_struct_MqS)(this), v)
C.free(unsafe.Pointer(v))
}

func (this *MqS) ConfigSetIdent(val string) {
v := C.CString(val)
C.MqConfigSetIdent((*_Ctype_struct_MqS)(this), v)
C.free(unsafe.Pointer(v))
}

//export cServerSetup
func (this *MqS) cServerSetup(cb *IServerSetup) {


defer func() {
if x := recover(); x != nil {

this.ErrorSet(x)
}
}()
this.LogC("cServerSetup",0,"1111111111111111111111\n")
(*cb).ServerSetup()
}

func (this *MqS) ConfigSetServerSetup(cb IServerSetup) {
println("1. ConfigSetServerSetup ... ", cb)
C.gomsgque_ConfigSetServerSetup((*_Ctype_struct_MqS)(this),
unsafe.Pointer(&cb))
}

func (this *MqS) ConfigSetServerCleanup(cb IServerCleanup) {
fmt.Printf("ConfigSetServerCleanup ... %T\n", cb)
C.MqConfigSetServerCleanup((*_Ctype_struct_MqS)(this), nil, nil, nil, nil)
}

/**
* \file theLink/gomsgque/src/service.go
* \brief \$Id: service.go 315 2010-11-19 10:33:21Z aotto1968 $
*
* (C) 2010 - NHI - #1 - Project - Group
*
* \version \$Rev: 315 $
* \author EMail: aotto1968 at users.berlios.de
* \attention this software has GPL permissions to copy
* please contact AUTHORS for additional information
*/

package gomsgque

/*
#include <gomsgque.h>
*/
import "C"

import (
//"fmt"
//"strings"
"unsafe"
)

//export cService
func (this *MqS) cService(cb *IService) {


defer func() {
if x := recover(); x != nil {

this.ErrorSet(x)
}
}()
this.LogC("cService",0,"1111111111111111111111\n")
(*cb).Call()
}

func (this *MqS) ServiceCreate(token string, cb IService) {
println("1. ServiceCreate ... ", cb)
t := C.CString(token)
C.gomsgque_ServiceCreate((*_Ctype_struct_MqS)(this), t,
unsafe.Pointer(&cb))
C.free(unsafe.Pointer(t))
}

func (this *MqS) ProcessEvent(timeout TIMEOUT, wait WAIT) {

this.iErrorMqToGoWithCheck(C.MqProcessEvent((*_Ctype_struct_MqS)(this),
C.MQ_TIME_T(timeout), uint32(wait)))
}


/**
* \file theLink/gomsgque/src/gomsgque.c
* \brief \$Id: gomsgque.c 315 2010-11-19 10:33:21Z aotto1968 $
*
* (C) 2010 - NHI - #1 - Project - Group
*
* \version \$Rev: 315 $
* \author EMail: aotto1968 at users.berlios.de
* \attention this software has GPL permissions to copy
* please contact AUTHORS for additional information
*/

#include "gomsgque.h"

MQ_CST sGO = "GO";
MQ_CST sUNKNOWN = "UNKNOWN";

static enum MqErrorE sServerSetup (
struct MqS * const context,
MQ_PTR const data
)
{
MqLogC(context,"sServerSetup",0,"INFO\n");
cServerSetup((int*)context->self, data);
return MqErrorStack(context);
}

void
gomsgque_ConfigSetServerSetup (
struct MqS * const context,
void *data
)
{
MqConfigSetServerSetup(context, sServerSetup, (MQ_PTR)data, NULL, NULL);
}

static enum MqErrorE sService (
struct MqS * const context,
MQ_PTR const data
)
{
MqLogC(context,"sService",0,"INFO\n");
cService((int*)context->self, data);
return MqErrorStack(context);
}

void
gomsgque_ServiceCreate (
struct MqS * const context,
MQ_TOK const token,
void *data
)
{
MqServiceCreate(context, token, sService, (MQ_PTR)data, NULL);
}

/**
* \file theLink/gomsgque/src/gomsgque.h
* \brief \$Id: gomsgque.h 315 2010-11-19 10:33:21Z aotto1968 $
*
* (C) 2010 - NHI - #1 - Project - Group
*
* \version \$Rev: 315 $
* \author EMail: aotto1968 at users.berlios.de
* \attention this software has GPL permissions to copy
* please contact AUTHORS for additional information
*/

#include <stdlib.h>
#include "msgque.h"
#include "debug.h"

extern MQ_CST sGO;
extern MQ_CST sUNKNOWN;

void gomsgque_ConfigSetServerSetup (struct MqS * const, void *data);
void gomsgque_ServiceCreate (struct MqS * const, MQ_TOK const token,
void *data);

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJM5lKOAAoJEGTcPijNG3/Amm8H/jZLkOSQY0IfBRov2enJVe2G
t03M6nO9924q973oKZTdnwIFDGkM8N7wqZablCXHpi410yXie6ZtQa/JDk0v0YLB
08WDdy0K60KVAmhHObIK8Fld1Nw4DH/eobxqL9GhTJpJfONReVD+k3s4Z1iSJUSG
nkYro0SzoLW+emaZi+CTNNTVPm1+o9nG3PIzQ14jZY9npc6L+7no9UNXaUPCp6+s
d9Tq9dHoQb3hHm677DTSiEHBkPEkcpty+oObUmtyx5qjQQlfo3Ewxh11L20KlAM+
QCfI4exT/DOkAYFnKAySRfKiU3r6OhVvwTUVGXq8QJa8nKkgjLiLQ4po50ZMvH0=
=JSso
-----END PGP SIGNATURE-----

roger peppe

unread,
Nov 19, 2010, 6:21:15 AM11/19/10
to Andreas Otto, chris dollin, golang-nuts
On 19 November 2010 10:04, Andreas Otto <aott...@t-online.de> wrote:
> 1. my problem is that I have one additional level of "indirection" using
> the following construct
> - -> MqCallback(func() {ret.ServerSetup()})
> All together I have the following Wrappers to call an arbitrary GO method
>
> 1. Wrapper in C
> 2. Wrapper in GO
> 3. func() wrapper in GO
> 4. finally -> method

i don't think that this (the C wrapping stuff) should affect what the package
API looks like.

i think you're still trying to use embedding too much, which makes your
problem appear more complex than it is, with a very twisty flow of control.

in fact, i don't think you strictly need the Server type at all, and if you
change the IService interface so that the MqS instance is passed in,
you don't need to store it in your service objects.

it is not usual in Go to allow panics to pass package boundaries - you
should put error returns on those routines that can fail, and do explicit
error checking.

here's how your main package could look. no embedding necessary,
which makes things clearer, i think.

package main

import (
"gomsgque"
"os"
)

type SharedState struct {
incr uint32
}

type ECOI struct {
state *SharedState
}

func (e ECOI) Call(mq *MqS) {
mq.SendSTART()
mq.SendI(mq.ReadI() + e.state.incr)
mq.SendRETURN()
}

func main() {
state := &SharedState{10}
mq := gomsgque.NewMqS()
mq.ServiceCreate("ECOI", ECOI{state})
mq.ServiceCreate("Foo", Foo{state})
... more services
mq.ConfigSetName("server")
mq.ConfigSetIdent("test-server")
mq.LinkCreate(os.Args...)
mq.LogC("test", 1, "this is the log test\n")
mq.ProcessEvent(MqS_TIMEOUT_DEFAULT, MqS_WAIT_FOREVER)
}

Andreas Otto

unread,
Nov 19, 2010, 6:38:59 AM11/19/10
to roger peppe, chris dollin, golang-nuts
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

This look good, but one restriction is also available not mentioned yet.
- -> *multiple* "Server" in one binary have to be possible.

the example shows only a *single* server solution, I already use this
style of programming for easy problems.
In addition I have a techology called "ServerOnServer"

http://nhi1.berlios.de/theLink/csmsgque/group__csmsgqueref.htm#cs_ClientServerLink

and for this scenario you need a distinct server object to separate
Server local variables.

The "ServerSetup" is required only for the multiple-server
problem, because the *first* toplevel server is responsible to
setup/create the "child" servers ...
but yes...

the single-server problem does not need a "ServerSetup"

be aware that the server technology have to be thread-safe as well.
this mean multiple toplever server in one binary have to coexist ....

but to make it short, I think I solved all possible problems
and you can code with or without distinct toplevel server object
depending on the complexity of the problem to solve.


mfg, Andreas Otto
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJM5mHTAAoJEGTcPijNG3/AzCQIAJlhCSPi6Uf+mMaY+D9nRxeK
VEvwrmSGQ1jMNe4Klbwys2ZEM2Ea2PQtY2UlPDp+1/tbqZqBznBlySqxyY4cq+E6
yK1Iy/Xnru3dyxov3QiAoQ74JsfjkHqhgsS8WBJqO2Bqqre1TnIN4BvUJP/1PCj5
YnEj14HgcP6r22nVX7+F98o559Ld0KFQoTxJ5IpVyCUSIqDhfD6igj118W04Y0jc
2jxm7SKIsFf7JsRy4rH+eCCQ33MSBlG6KCwZgrpEcj6Hli59gCJ5YrW3IYdD4GrO
y8vUK6DxxW7tUkJwYPqgDQo+gVZjT6ArLrG0msnRNYkkxMKQ8iowUnq3tAKwhrA=
=29h1
-----END PGP SIGNATURE-----

roger peppe

unread,
Nov 19, 2010, 6:59:38 AM11/19/10
to Andreas Otto, chris dollin, golang-nuts
On 19 November 2010 11:38, Andreas Otto <aott...@t-online.de> wrote:
> the example shows only a *single* server solution, I already use this
> style of programming for easy problems.
> In addition I have a techology called "ServerOnServer"
>
> http://nhi1.berlios.de/theLink/csmsgque/group__csmsgqueref.htm#cs_ClientServerLink
>
> and for this scenario you need a distinct server object to separate
> Server local variables.
>
> The "ServerSetup" is required only for the multiple-server
> problem, because the *first* toplevel server is responsible to
> setup/create the "child" servers ...
> but yes...
>
> the single-server problem does not need a "ServerSetup"

i think you could easily do multiple servers with the code
i proposed - just embed the other servers inside one
of the services (assuming i understand correctly what your code is doing,
which i probably don't!)

there's no reason why the separate services have to share
the same SharedState - SharedState is just a placeholder for
any state that's in common between any given set of services.

i don't see that the Server abstraction in your code gives you
anything more than setup and teardown callbacks - and those
can easily (and more directly) be done on the caller's side.

in your code, MqS is embedded directly within Server - what's
the real distinction between MqS and Server?

Andreas Otto

unread,
Nov 19, 2010, 1:36:26 PM11/19/10
to roger peppe, chris dollin, golang-nuts
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1


Hi,

this are the first performance results ...

1. C only -> should be the fastest

> ./client @ ./server
C> (client:9015:0x7f5c5560f700) [2010-11-19:19-25-38]
[0-0-0-0x62d780-main]: start: --------------------------------------
C> (client:9015:0x7f5c5560f700) [2010-11-19:19-25-39]
[0-0-0-0x62d780-statistics]: MqSendEND_AND_WAIT: 19.29
C> (client:9015:0x7f5c5560f700) [2010-11-19:19-25-39]
[0-0-0-0x62d780-main]: end: ----------------------------------------


2. C#
> csharp.env ./client @ MONO csserver.exe
C> (client:9019:0x7f46aa809700) [2010-11-19:19-26-04]
[0-0-0-0x62d8a0-main]: start: --------------------------------------
C> (client:9019:0x7f46aa809700) [2010-11-19:19-26-05]
[0-0-0-0x62d8a0-statistics]: MqSendEND_AND_WAIT: 20.72
C> (client:9019:0x7f46aa809700) [2010-11-19:19-26-05]
[0-0-0-0x62d8a0-main]: end: ----------------------------------------


3. JAVA
> java.env ./client @ JAVA example/Server
C> (client:13460:0x7f529fba5700) [2010-11-19:19-28-47]
[0-0-0-0x62d8a0-main]: start: --------------------------------------
C> (client:13460:0x7f529fba5700) [2010-11-19:19-28-48]
[0-0-0-0x62d8a0-statistics]: MqSendEND_AND_WAIT: 22.68
C> (client:13460:0x7f529fba5700) [2010-11-19:19-28-48]
[0-0-0-0x62d8a0-main]: end: ----------------------------------------


4. GO
> ./client @ ../gomsgque/src/server
C> (client:9027:0x7f317cda1700) [2010-11-19:19-27-05]
[0-0-0-0x62d780-main]: start: --------------------------------------
C> (client:9027:0x7f317cda1700) [2010-11-19:19-27-06]
[0-0-0-0x62d780-statistics]: MqSendEND_AND_WAIT: 23.94
C> (client:9027:0x7f317cda1700) [2010-11-19:19-27-06]
[0-0-0-0x62d780-main]: end: ----------------------------------------


I'm disappointed from GO ... probably to mutch indirection ??


This is the GO server .....

package main

import (
. "gomsgque"
"os"
)

type Server struct {
*MqS
}

func NewServer() *Server {
ret := &Server{NewMqS()}
ret.ConfigSetServerSetup(ret)
return ret
}

func (this *Server) ServerSetup() {
this.ServiceCreate("ECOI", &ECOI{this})

this.ServiceCreate("ECOU", &ECOU{this})
this.ServiceCreate("ECUL", &ECUL{this})
}

type ECOI struct { *Server }
func (this *ECOI) Call() {
this.SendSTART()

this.SendI(this.ReadI())
this.SendRETURN()
}

type ECOU struct { *Server }
func (this *ECOU) Call() {
this.SendSTART()
this.SendU(this.ReadU())
this.SendRETURN()
}

type ECUL struct { *Server }
func (this *ECUL) Call() {
this.SendSTART()
this.SendY(this.ReadY())
this.SendS(this.ReadS())
this.SendI(this.ReadI())
this.SendW(this.ReadW())
this.ReadProxy(this.Server.MqS)
this.SendRETURN()
}

func main() {
var srv = NewServer()
defer func() {
if x := recover(); x != nil {
srv.ErrorSet(x)
}
srv.Exit()
}()
srv.ConfigSetName("server")
srv.ConfigSetIdent("test-server")
srv.LinkCreate(os.Args...)

srv.LogC("test",1,"this is the log test\n")
srv.ProcessEvent(MqS_TIMEOUT_DEFAULT, MqS_WAIT_FOREVER)
}


mfg, Andreas Otto
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJM5sOqAAoJEGTcPijNG3/Aj5oH/R4HwdtD42NaD3hytRu65ek4
YuA+3kFKBEVDoGKpL6cId30qoFj5Vb5bCz2V0qOG9+a3nNw76UEfYNeGyjWN5Y+t
bpAmzvtcWyT5y8cad4TYVIXSQNC5OQP7yD05yabGbRVBQVqLRZk/9bzKy+o92jV9
1NzgsWTwN9aimTxYd0sQ5Cdz0yQttFBof2BQo7M691bIqQcYB3cOjRogb8BPpxAw
vM/TDgPMbvbWjOt1g0k22LkeDgrX1B2MSItGaEIrbSjtwlMb0XQar3TC39BkwVjz
Ivw77Kapp5oSDSMYW2ZUEjVQh7y7qTRcLOvT1BlJ69FtHMrXOB8RT6q3Zo95AXw=
=QLF9
-----END PGP SIGNATURE-----

Cory Mainwaring

unread,
Nov 19, 2010, 1:45:07 PM11/19/10
to Andreas Otto, roger peppe, chris dollin, golang-nuts
Pure Go is usually within 50% of C. Most of the extra performance hit
is from getting into and out of the C code. Try to get the C code
you're wrapping to do more at a time, and you reduce that penalty.

Andreas Otto

unread,
Nov 19, 2010, 1:56:59 PM11/19/10
to Cory Mainwaring, roger peppe, chris dollin, golang-nuts
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Am 19.11.2010 19:45, schrieb Cory Mainwaring:
> Pure Go is usually within 50% of C. Most of the extra performance hit
> is from getting into and out of the C code. Try to get the C code
> you're wrapping to do more at a time, and you reduce that penalty.
>
> On 19 November 2010 13:36, Andreas Otto <aott...@t-online.de> wrote:
>

> ...
> type Server struct {
> *MqS
> }
> ...

> type ECUL struct { *Server }
> func (this *ECUL) Call() {
> this.SendSTART()
> this.SendY(this.ReadY())
> this.SendS(this.ReadS())
> this.SendI(this.ReadI())
> this.SendW(this.ReadW())
> this.ReadProxy(this.Server.MqS)
> this.SendRETURN()
> }
>

I think the problem is the triple pointer de-referencing in the service
from the "embedded" code

> type Server struct { *MqS }
and
> type ECUL struct { *Server }

this mean "this.SendSTART" end op with "this.Server.MqS.SendSTART..."

I don't know if GO is smart enough to do the triple de-referencing
only once and not for every "this" !!!

the current performance is a scripting-language performance ...
I expect to be on C# performance level

Skipping the "Server" type (as mentioned before) should delete one
in-direction level ....

- -> but I don't know if this would be a good idea

I need more testing for the different coding->style's of GO


mfg, Andreas Otto
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJM5sh6AAoJEGTcPijNG3/AHs8H/R+jp+ox4tovTr5Tob/EPbLf
5CqJNqHd6BldNnZbuqhKraaB0H31awjPhteV1cyYCT8TXqv9HkD6jRQmToKjf5NB
6/4D/AXc9pqqH/zHBfABcdf6o+JiJbNo86GybowMqHaelxoCvNtgmubLYL5L3PGB
ZnBJAmWNftmemBuDeEmKjJJEu8+dI3gxCb09RqNoU1IQ4psSFQqe/aWKUMHFbHxt
sKMnbAuGyfvi2XHWiKqFcCeL+Lb7nlcLxi7WmPpknzxbmiZfD6c1kUp4ThgwhLsn
/m2aWTUELVcxl8TNvd/wbEYRzZ+UB06CLAZzi7BpZfJgzWQMtpBhE52p/MgWuQ8=
=lkHZ
-----END PGP SIGNATURE-----

Steven

unread,
Nov 19, 2010, 3:55:34 PM11/19/10
to Andreas Otto, Cory Mainwaring, roger peppe, chris dollin, golang-nuts
On Friday, November 19, 2010, Andreas Otto <aott...@t-online.de> wrote:
>
> I think the problem is the triple pointer de-referencing in the service
> from the "embedded" code
>
Calling C code does cause a major performance hit if it isn't doing
much work. Bridging between the two is non-trivial, due to differing
calling conventions, stack structure, scheduling, and garbage
collection.

>> type Server struct { *MqS }
> and
>> type ECUL struct { *Server }
>
> this mean "this.SendSTART" end op with "this.Server.MqS.SendSTART..."
>
> I don't know if GO is smart enough to do the triple de-referencing
> only once and not for every "this" !!!
>

Maybe you should not create a veritable linked list you have to
traverse for every method call, rather than need Go to be "smart
enough" to figure out that you aren't altering that linked list
between calls ;-). You can embed structs instead of pointers to them.

Andreas Otto

unread,
Nov 21, 2010, 5:24:50 AM11/21/10
to Cory Mainwaring, roger peppe, chris dollin, golang-nuts
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,

I do more tests ...


1. Original:
func (this *Server) ServerSetup() {


this.ServiceCreate("ECUL", &ECUL{this})
}

type ECUL struct { *Server }
func (this *ECUL) Call() {
this.SendSTART()
this.SendY(this.ReadY())
this.SendS(this.ReadS())
this.SendI(this.ReadI())
this.SendW(this.ReadW())
this.ReadProxy(this.Server.MqS)
this.SendRETURN()
}

> ./client @ ../gomsgque/src/server
C> (client:7839:0x7f0667c18700) [2010-11-21:09-25-53]
[0-0-0-0x62d780-main]: start: --------------------------------------
C> (client:7839:0x7f0667c18700) [2010-11-21:09-25-54]
[0-0-0-0x62d780-statistics]: MqSendEND_AND_WAIT: 22.50
C> (client:7839:0x7f0667c18700) [2010-11-21:09-25-54]
[0-0-0-0x62d780-main]: end: ----------------------------------------

2. replace this


type ECUL struct { *Server }
func (this *ECUL) Call() {

ctx := this.Server.MqS
ctx.SendSTART()
ctx.SendY(ctx.ReadY())
ctx.SendS(ctx.ReadS())
ctx.SendI(ctx.ReadI())
ctx.SendW(ctx.ReadW())
ctx.ReadProxy(ctx)
ctx.SendRETURN()
}

> ./client @ ../gomsgque/src/server
C> (client:7811:0x7fbb8538d700) [2010-11-21:09-24-47]
[0-0-0-0x62d780-main]: start: --------------------------------------
C> (client:7811:0x7fbb8538d700) [2010-11-21:09-24-48]
[0-0-0-0x62d780-statistics]: MqSendEND_AND_WAIT: 22.47
C> (client:7811:0x7fbb8538d700) [2010-11-21:09-24-48]
[0-0-0-0x62d780-main]: end: ----------------------------------------

3. replace service de-reference
func (this *Server) ServerSetup() {
this.ServiceCreate("ECUL", (*ECUL)(this))
}
type ECUL Server
func (this *ECUL) Call() {
ctx := this.MqS
ctx.SendSTART()
ctx.SendY(ctx.ReadY())
ctx.SendS(ctx.ReadS())
ctx.SendI(ctx.ReadI())
ctx.SendW(ctx.ReadW())
ctx.ReadProxy(ctx)
ctx.SendRETURN()
}
> ./client @ ../gomsgque/src/server
C> (client:7783:0x7f4e07f6c700) [2010-11-21:09-23-54]
[0-0-0-0x62d780-main]: start: --------------------------------------
C> (client:7783:0x7f4e07f6c700) [2010-11-21:09-23-55]
[0-0-0-0x62d780-statistics]: MqSendEND_AND_WAIT: 22.45
C> (client:7783:0x7f4e07f6c700) [2010-11-21:09-23-55]
[0-0-0-0x62d780-main]: end: ----------------------------------------

==> all three tests does not show up any performance improvement

4.
New try -> skip "C" callback and try to call "GO" callback directly from
"libmsgque"

//export gomsgque_cService
func (this *MqS) cService(cb *Service) uint32 {


defer func() {
if x := recover(); x != nil {

this.ErrorSet(x)
}
}()
(*cb).Call()
return C.MqErrorGetCode((*_Ctype_struct_MqS)(this))
}

func (this *MqS) ServiceCreate(token string, cb Service) {


t := C.CString(token)
C.gomsgque_ServiceCreate((*_Ctype_struct_MqS)(this), t,
unsafe.Pointer(&cb))
C.free(unsafe.Pointer(t))
}

void
gomsgque_ServiceCreate (
struct MqS * const context,
MQ_TOK const token,
void *data
)
{

MqServiceCreate(context, token, (MqTokenF)gomsgque_cService,
(MQ_PTR)data, NULL);
}

RESULT
> ./client @ ../gomsgque/src/server
C> (client:9683:0x7fcf9d7a7700) [2010-11-21:09-47-14]
[0-0-0-0x62d780-main]: start: --------------------------------------
C> (client:9683:0x7fcf9d7a7700) [2010-11-21:09-47-15]
[0-0-0-0x62d780-statistics]: MqSendEND_AND_WAIT: 22.52
C> (client:9683:0x7fcf9d7a7700) [2010-11-21:09-47-15]
[0-0-0-0x62d780-main]: end: ----------------------------------------

- --> same result nothing help

Just to remember, we other results
!C! > ./client @ ./server
C> (client:11949:0x7fd207171700) [2010-11-21:09-50-19]
[0-0-0-0x62d780-main]: start: --------------------------------------
C> (client:11949:0x7fd207171700) [2010-11-21:09-50-20]
[0-0-0-0x62d780-statistics]: MqSendEND_AND_WAIT: 18.35
C> (client:11949:0x7fd207171700) [2010-11-21:09-50-20]
[0-0-0-0x62d780-main]: end: ----------------------------------------
!C#! > csharp.env ./client @ MONO csserver.exe
C> (client:11953:0x7f842a2d5700) [2010-11-21:09-50-39]
[0-0-0-0x62d8a0-main]: start: --------------------------------------
C> (client:11953:0x7f842a2d5700) [2010-11-21:09-50-40]
[0-0-0-0x62d8a0-statistics]: MqSendEND_AND_WAIT: 19.60
C> (client:11953:0x7f842a2d5700) [2010-11-21:09-50-40]
[0-0-0-0x62d8a0-main]: end: ----------------------------------------
!JAVA! > java.env ./client @ JAVA example/Server
C> (client:11961:0x7f6554830700) [2010-11-21:09-51-05]
[0-0-0-0x62d8a0-main]: start: --------------------------------------
C> (client:11961:0x7f6554830700) [2010-11-21:09-51-06]
[0-0-0-0x62d8a0-statistics]: MqSendEND_AND_WAIT: 21.30
C> (client:11961:0x7f6554830700) [2010-11-21:09-51-06]
[0-0-0-0x62d8a0-main]: end: ----------------------------------------


=============================================================================

Next try embedding MqS struct and not the pointer

CODE:
package gomsgque
// for toplevel "MqS"


func NewMqS() *MqS {
this := C.MqContextCreate(0,nil)
C.MqConfigSetSelf(this, unsafe.Pointer(this))

return (*MqS)(this)
}

// for embedding "MqS"
func (this *MqS) Init() {
C.MqContextInit((*_Ctype_struct_MqS)(this), 0,nil)
C.MqConfigSetSelf((*_Ctype_struct_MqS)(this), unsafe.Pointer(this))
}

1. embedding
package main
type Server struct {
MqS
}
func NewServer() *Server {
ret := new(Server)
ret.Init()
ret.ConfigSetServerSetup(ret)
return ret
}
type ECUL Server
func (this *ECUL) Call() {
ctx := &this.MqS
ctx.SendSTART()
ctx.SendY(ctx.ReadY())
ctx.SendS(ctx.ReadS())
ctx.SendI(ctx.ReadI())
ctx.SendW(ctx.ReadW())
ctx.ReadProxy(ctx)
ctx.SendRETURN()
}

RESULT
> ./client @ ../gomsgque/src/server
C> (client:13868:0x7fb7aba11700) [2010-11-21:10-23-12]
[0-0-0-0x62d780-main]: start: --------------------------------------
C> (client:13868:0x7fb7aba11700) [2010-11-21:10-23-13]
[0-0-0-0x62d780-statistics]: MqSendEND_AND_WAIT: 22.85
C> (client:13868:0x7fb7aba11700) [2010-11-21:10-23-13]
[0-0-0-0x62d780-main]: end: ----------------------------------------


ANALYZE: the problem is that in "C" you can do a "Pointer-cast"
if the embedded struct is the fist object and the
pointer-address of *Server is equal to *MqS

MqS *ctx = (MqS*)(server) -> the is a "O" time operation

In go this is !not! allowed -> and you end-up in something like

MqS *ctx = &(server->MqS)

- -> this is still a kind of double-de-reference problem

code: ctx := (*MqS)(this)
compile error: server.go:53: cannot convert this (type *ECUL) to type
*gomsgque.MqS
or: ctx := (*MqS)((*Server)(this))
- ->: server.go:53: cannot convert (*Server)(this) (type *Server) to type
*gomsgque.MqS


2. referencing


type Server struct {
*MqS
}
func NewServer() *Server {
ret := &Server{NewMqS()}
ret.ConfigSetServerSetup(ret)
return ret
}

type ECUL Server
func (this *ECUL) Call() {
ctx := this.MqS
ctx.SendSTART()
ctx.SendY(ctx.ReadY())
ctx.SendS(ctx.ReadS())
ctx.SendI(ctx.ReadI())
ctx.SendW(ctx.ReadW())
ctx.ReadProxy(ctx)
ctx.SendRETURN()
}
RESULT:
> ./client @ ../gomsgque/src/server
C> (client:13957:0x7f8c06f87700) [2010-11-21:10-25-54]
[0-0-0-0x62d780-main]: start: --------------------------------------
C> (client:13957:0x7f8c06f87700) [2010-11-21:10-25-55]
[0-0-0-0x62d780-statistics]: MqSendEND_AND_WAIT: 22.62
C> (client:13957:0x7f8c06f87700) [2010-11-21:10-25-55]
[0-0-0-0x62d780-main]: end: ----------------------------------------

- -> not real a difference

It doesn't matter how to program "GO" there is a "hidden" wall at "22.*"


##########################################################

next try provide "*MqS" as interface argument

package gomsgque
type Service interface {
Call(*MqS)
}
//export gomsgque_cService
func (this *MqS) cService(cb *Service) uint32 {


defer func() {
if x := recover(); x != nil {

this.ErrorSet(x)
}
}()
(*cb).Call(this)
//return C.MqErrorGetCode((*_Ctype_struct_MqS)(this))
return this.error.code
}
package main
type ECUL Server
func (this *ECUL) Call(ctx *MqS) {
ctx.SendSTART()
ctx.SendY(ctx.ReadY())
ctx.SendS(ctx.ReadS())
ctx.SendI(ctx.ReadI())
ctx.SendW(ctx.ReadW())
ctx.ReadProxy(ctx)
ctx.SendRETURN()
}
RESULT:
> ./client @ ../gomsgque/src/server
C> (client:14829:0x7f7f04e1f700) [2010-11-21:10-56-23]
[0-0-0-0x62d780-main]: start: --------------------------------------
C> (client:14829:0x7f7f04e1f700) [2010-11-21:10-56-24]
[0-0-0-0x62d780-statistics]: MqSendEND_AND_WAIT: 22.60
C> (client:14829:0x7f7f04e1f700) [2010-11-21:10-56-24]
[0-0-0-0x62d780-main]: end: ----------------------------------------

- -> nothing help, still the "22.*" wall

next try -> skip the "recover" part from cService
//export gomsgque_cService
func (this *MqS) cService(cb *Service) uint32 {
(*cb).Call(this)
//return C.MqErrorGetCode((*_Ctype_struct_MqS)(this))
return this.error.code
}

RESULT: The Target Is Moving !!!!!!
> ./client @ ../gomsgque/src/server
C> (client:14994:0x7fc65c08f700) [2010-11-21:10-58-29]
[0-0-0-0x62d780-main]: start: --------------------------------------
C> (client:14994:0x7fc65c08f700) [2010-11-21:10-58-30]
[0-0-0-0x62d780-statistics]: MqSendEND_AND_WAIT: 21.87
C> (client:14994:0x7fc65c08f700) [2010-11-21:10-58-30]
[0-0-0-0x62d780-main]: end: ----------------------------------------

the problem is that I need the "rescue" part to report errors from the
server to the client and "continue" the server . without this part every
"panic" will end up in a toplevel "panic" and shutdown the server -> BAD

one problem is that


defer func() {
if x := recover(); x != nil {

this.ErrorSet(x)
}
}()
will "*always*" evaluate... not only on error -> bad technology
- -> "try ... catch" would be better


mfg, Andreas Otto
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJM6PNyAAoJEGTcPijNG3/AnvMH/3CQ5sVBhY8+3gPgEm6AMj0O
eKc6ea8lqfREYJ2hWz2NCqMPUAS7JDej7SXDsqeKb5zRSkhK8ZrGJExUmt1ghDTx
ovpycNkMGb6/RQgDR9XshOy/Dpvp6D1gh0DawCyh76IERyBbLVykXZrEPBLoXKNi
8n+p47guDFDoDniaff2AizUcX0yB/qmmCUaCZxBR2ZU8F+0JtTvnjCpspBZlEhXo
cn0CsQb5yR7t2xRLNRktAHvDBQ94FJCsflKmtnqjMr1MTS5zEJNoiJWH91lphT+7
nZZGJW1TvhWRJju8gdDWHXMZH4BvDaFJ9YTgPg03JT4rH+KQSdxpPCwxwws+z/4=
=CtEp
-----END PGP SIGNATURE-----

Cory Mainwaring

unread,
Nov 21, 2010, 5:47:54 AM11/21/10
to Andreas Otto, roger peppe, chris dollin, golang-nuts
The performance wall isn't in the defer, it's in the Go -> C
transition. Every C function is expensive because it has 3 steps:
"Convert to C types", "Run C function", "Convert to Go types".

If you're dead-set on not re-writing this MqS library in Go, then your
main bottleneck is functions that look like this:

func (this *ECUL) Call() {
ctx := &this.MqS
ctx.SendSTART()
ctx.SendY(ctx.ReadY())
ctx.SendS(ctx.ReadS())
ctx.SendI(ctx.ReadI())
ctx.SendW(ctx.ReadW())
ctx.ReadProxy(ctx)
ctx.SendRETURN()
}

Each one of those method calls is more expensive than you think it is.
They all have the three steps. Try re-writing it so that it's just one
call into C, with C then doing that series of function calls. It will
save you 10 conversions to C. Also, find other areas like this, where
you have a bevy of function calls that each go into C, and combine
them so there's only 1 conversion into C.

Andreas Otto

unread,
Nov 21, 2010, 6:11:42 AM11/21/10
to Cory Mainwaring, roger peppe, chris dollin, golang-nuts
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Am 21.11.2010 11:47, schrieb Cory Mainwaring:
> The performance wall isn't in the defer, it's in the Go -> C
> transition. Every C function is expensive because it has 3 steps:
> "Convert to C types", "Run C function", "Convert to Go types".
>
> If you're dead-set on not re-writing this MqS library in Go, then your
> main bottleneck is functions that look like this:

if I ANNOUNCE the availability of "gomsgque" I write a couple of lines
why I choose this approach and do not re-writing the "libmsgque" library
for every language again.

mfg, Andreas Otto
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJM6P5uAAoJEGTcPijNG3/AV9YH/i80UAtpeitEWKsaNWC7qbHu
Ia/pJrtft32pvIPfnDYgpgEB12FuTvfG3qfqFYg64oMsXjknDTbJnwN61umr4Olz
w8mKMEFdTVCpfVrXYbdhBYAkjVgrBeiUDx/0gQ1UVwlmKAdAtFKDngNYfueABsju
mmoFAvgSzvte3OhsFcP/JAPDWLdJ6QQDTrGeAM/jDYu1n5O58AHnH7T/pWF85BzY
dNYopQoA/9fdmMGKumuBudTLcRadnUkXPm3M40mLxjcY/xyePwnpbFzUj9iRMyRl
jC3XWVQn4sjtbc4mbsyPEGEmIR/uzlSPJY06/pMpNzsxMNjW5kHuFaQSjWPAvvI=
=gasN
-----END PGP SIGNATURE-----

Andreas Otto

unread,
Nov 21, 2010, 6:12:02 AM11/21/10
to Cory Mainwaring, roger peppe, chris dollin, golang-nuts
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Am 21.11.2010 11:47, schrieb Cory Mainwaring:
> The performance wall isn't in the defer, it's in the Go -> C
> transition. Every C function is expensive because it has 3 steps:
> "Convert to C types", "Run C function", "Convert to Go types".
>
> If you're dead-set on not re-writing this MqS library in Go, then your
> main bottleneck is functions that look like this:
>
> func (this *ECUL) Call() {
> ctx := &this.MqS
> ctx.SendSTART()
> ctx.SendY(ctx.ReadY())
> ctx.SendS(ctx.ReadS())
> ctx.SendI(ctx.ReadI())
> ctx.SendW(ctx.ReadW())
> ctx.ReadProxy(ctx)
> ctx.SendRETURN()
> }
>

Hi,

just for understanding ...
I can write the "ECUL" code entire in "C" and just call the
toplevel "ECUL" from GO -> this will be definitely
faster. But this is not the goal of the test. The goal
is to test how expensive is the call from Go to C. for the
"other" languages I have done the same setup as in GO
above.

For me the performance is OK ... flower than expected but
faster as typical "scripting" languages.
I just wondering why C#/mono (19.*) is faster than GO (22.*)
for doing the same job?


mfg, Andreas Otto
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJM6P6CAAoJEGTcPijNG3/AASsIAJs4m8+Sxrkl4unoevMPyQby
i0EBTxkzjYqXZgCOx2o0z/siVMI0Dx1JKGFr3DpESiAWgtUqeLBIr9JRXxkyZCI4
66fGAIgbCNpZRf25dZz7e49sMiUQZZrwSK2iQAMG63KHBaLe4X/MhGarqpmVs647
GyyWRZ5znM4F7OK8rUgN26gGNqAheKb9L1fBcZHg+Yl1wrPGKemTuLRNLIOAWDY2
qEPtT3Jeojc1bkPMl1GVXjA9ftu5R+ItZa8zgJ8GoJaW1oNZN+Sn6E7ExFLdvHoo
kjOlFe7HX3GX+8j4zejdeZ+5YMtO9DEpTeFKGf0o7HVvCZoS+gg0WQmFy0CZzGs=
=VF1p
-----END PGP SIGNATURE-----

Cory Mainwaring

unread,
Nov 21, 2010, 6:41:39 AM11/21/10
to Andreas Otto, golang-nuts
Go uses an entirely different calling structure than C# I believe.
Meaning that the conversion to C99 is more difficult for Go. For a
more detailed analysis, you'd probably have to look at the code of Cgo
or wait for Russ to pipe in. I didn't think Java used the C99 calling
structure though, so that would probably be the most interesting case
(though if it does, then it's just because Go has to do more work to
get into C).

pgavlin

unread,
Nov 21, 2010, 11:19:06 AM11/21/10
to golang-nuts
On Nov 21, 5:41 am, Cory Mainwaring <olre...@gmail.com> wrote:
> Go uses an entirely different calling structure than C# I believe.
IIRC, the Go calling convention uses the stack for all function/method
arguments
and return values. For i386, there may not be much overhead: although
there is
no single calling convention, the typical calling conventions for
Linux and
Windows (i.e. cdecl/gcc and stdcall) both accept parameters on the
stack,
with the single return value in EAX. amd64 is a bit more complicated,
however:
both Microsoft's ABI and the canonical AMD64 ABI pass a number of
arguments
in registers. On these systems, then, there will be overhead incurred
when copying
any necessary arguments from the stack into the appropriate
registers.
Taking a brief look at the output of cgo, it would appear that cgo
emits C source
which knows the Go calling convention. This C is then compiled (by
gcc) and
linked against the output of the Go toolchain (some good examples of
the process are in
$GOROOT/misc/cgo). Thus, the number of calls is doubled when calling
a
C library using C.[function]. When calls are further wrapped (e.g.
functions
like "func (this *MqS) SendEND_AND_WAIT(token string, timeout
TIMEOUT)"),
additional overhead is incurred. Although it may be more efficient
for the Go
toolchain to emit appropriate assembly, it would likely add a great
deal of
complexity in order to deal with data layout, calling conventions,
etc. Perhaps
the C# toolchain is able to do something along these lines which
speeds things
up.

> Meaning that the conversion to C99 is more difficult for Go. For a
> more detailed analysis, you'd probably have to look at the code of Cgo
> or wait for Russ to pipe in. I didn't think Java used the C99 calling
> structure though, so that would probably be the most interesting case
> (though if it does, then it's just because Go has to do more work to
> get into C).
>
> > Comment: Using GnuPG with SUSE -http://enigmail.mozdev.org/

Andreas Otto

unread,
Nov 22, 2010, 6:46:38 AM11/22/10
to roger peppe, chris dollin, golang-nuts
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi roger,

after additional testing I think I'll go the way you
mentioned ... splitting the "Server" type from the
"MqS" type to avoid "expensive" dependencies.

the example server looks like:

package main

import (
. "gomsgque"
"os"
)

type MyServer struct {
// add server specific data
}

func NewMyServer() *MqS {
ctx := NewMqS()
srv := new(MyServer)
ctx.ConfigSetServerSetup(srv)
ctx.ConfigSetFactory(srv)
return ctx
}

func (this *MyServer) Factory(ctx *MqS) *MqS {
return NewMyServer()
}

func (this *MyServer) ServerSetup(ctx *MqS) {
ctx.ServiceCreate("HLWO", (*MyFirstService)(this))
}

type MyFirstService MyServer
func (this *MyFirstService) Call(ctx *MqS) {
ctx.SendSTART()
ctx.SendC("Hello World")
ctx.SendRETURN()
}

func main() {
var srv = NewMyServer()


defer func() {
if x := recover(); x != nil {
srv.ErrorSet(x)
}
srv.Exit()
}()

srv.LinkCreate(os.Args...)
srv.ProcessEvent(MqS_TIMEOUT_DEFAULT, MqS_WAIT_FOREVER)
}


mfg, Andreas Otto
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.15 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJM6lgeAAoJEGTcPijNG3/AqgMIAJuU+JiQ2oXpCmGA4aCELn7P
5lNqWMdZmZt3t0iWWgginER6MMsLyeMjSZuqBfOxudFItGdSwEZsOKoXdNr9FTQX
oVnBd6fCkZSwhHegRu4w7Vjw9HzlffBBLjlBVI+QHw4+NK19CxnuIJkE45IlSHJl
YLdRQxhbreboByZyJNYCcjNpJ9374IGRsReUhG+2CEu2Hvd00XscVRTpa7AGgcn6
GjjZT1OeSqaS/oAJdgxOsRvuHDhqkvt/YQDF4qWY+f71HrVYUbDblOhuzksvQotC
QkKfNzJrgAItnTTdmcRO61hsvhHyDdzlCvdBfrXm31MXnDwb7jpfl/1P3IblCFA=
=9bK5
-----END PGP SIGNATURE-----

gnu.bash

unread,
Nov 22, 2010, 2:05:59 PM11/22/10
to golang-nuts
Hi,

thanks for the very good answer

mfg, Andreas Otto

Reply all
Reply to author
Forward
0 new messages