aboutsummaryrefslogtreecommitdiff
path: root/main.go
blob: 4300ae4fe9879174a4763e55760a74c7aebd52f9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
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

}

Snix LLC Git Repository Holder Copyright(C) 2022 All Rights Reserved Email To Snix.IR