package main
import (
"crypto/rand"
"encoding/hex"
"fmt"
"gosema/sysv"
"os"
"time"
"golang.org/x/sys/unix"
)
/*
an example of ipc sysv with golang - this can be done with newer apis
like shm_open(), /dev/shm or mmap() too, sysv is the oldest way to do
this, and it's commonly used.
author: sina@snix.ir
*/
const (
//SHMSEMFLG = 0666 | unix.IPC_CREAT | unix.IPC_EXCL
SHMSEMFLG = 0666 | unix.IPC_CREAT // open shm and sem with this flag
SEMSHEMID = 0x12 // shm and sem id
NUMSOFSEM = 0x01 // number of sems
SHRDMEMRY = 0x20 // size of shared memory (32 byte)
)
const SEM_A = 0x00
func clntOrServ() bool {
if os.Args[1] == server {
return true
}
if os.Args[1] != client {
usage(os.Args[0])
}
return false
}
func main() {
defer defexit()
if len(os.Args) < 2 {
usage(os.Args[0])
}
serv := clntOrServ()
semkey, err := sysv.Ftok(os.DevNull, SEMSHEMID)
if err != nil {
fatal(err)
}
shmkey, err := sysv.Ftok(os.DevNull, SEMSHEMID)
if err != nil {
fatal(err)
}
shmidd, err := unix.SysvShmGet(int(shmkey), SHRDMEMRY, SHMSEMFLG)
if err != nil {
fatal(err)
}
defer unix.SysvShmCtl(shmidd, unix.IPC_RMID, &unix.SysvShmDesc{})
mem, err := unix.SysvShmAttach(shmidd, 0, 0)
if err != nil {
fatal(err)
}
defer unix.SysvShmDetach(mem)
if len(mem) != SHRDMEMRY {
fatal(errNotSame)
}
logst("shared memory is now ready to use", SHRDMEMRY)
sempht, err := sysv.NewSemGet(int(semkey), NUMSOFSEM, SHMSEMFLG)
if err != nil {
fatal(err)
}
defer sempht.DelSem()
// set semval to 1, which force client to wait for semaphore
switch {
case serv:
if err := sempht.SetVal(SEM_A, 1); err != nil {
warng(err)
}
for {
l, _ := sempht.GetVal(SEM_A) // value of semaphore
s, _ := sempht.GetPID(SEM_A) // pid that holds semaphore
fmt.Printf("sem locked by process pid: %d, semval: %d\n", s, l)
// lock sem[0], make semval = semval-1 and if semval is 0 then no one
// can lock semaphore any more
if err := sempht.Lock(SEM_A); err != nil {
warng(err)
continue
}
// l, _ = sempht.GetVal(SEM_A)
// fmt.Println(l)
// write some dummy random data to shared mem
if err := makeRand(mem); err != nil {
warng(err)
}
time.Sleep(time.Second) // every one sec
fmt.Println("i just put some random jokes in memory.. yeay")
if err := sempht.Unlock(SEM_A); err != nil {
warng(err)
} //unlock sem[0], make semval = semval+1
}
}
for {
if err := sempht.Lock(SEM_A); err != nil {
warng(err)
continue // do not unlock it if you haven't locked it
}
fmt.Printf("data: %s\n", hex.EncodeToString(mem))
if err := sempht.Unlock(SEM_A); err != nil {
warng(err)
}
}
}
func makeRand(b []byte) error {
_, err := rand.Read(b)
return err
}