Rune - Threaded function detach work
[rune.git] / libruntime / sys_misc.c
1 /*
2  * SYS_MISC.C
3  *
4  * Miscellanious system support
5  */
6
7 #include "defs.h"
8
9 struct bcopy_args {
10         PointerStor     s;
11         PointerStor     d;
12         runesize_t      bytes;
13 };
14
15 struct new_args {
16         LValueStor      lvs;
17         runesize_t      count;
18 };
19
20 void
21 RuneSysCall_bcopy(struct bcopy_args *args, void *rval __unused)
22 {
23         uintptr_t swrap;
24         uintptr_t dwrap;
25
26         swrap = (uintptr_t)args->s.s_Addr + args->bytes;
27         dwrap = (uintptr_t)args->d.s_Addr + args->bytes;
28         if (args->bytes > 0) {
29                 dassert(args->s.s_Addr >= args->s.s_Beg &&
30                         swrap <= (uintptr_t)args->s.s_End &&
31                         swrap >= (uintptr_t)args->s.s_Addr &&
32                         args->d.s_Addr >= args->d.s_Beg &&
33                         dwrap <= (uintptr_t)args->d.s_End &&
34                         dwrap >= (uintptr_t)args->d.s_Addr);
35                 bcopy(args->s.s_Addr, args->d.s_Addr, args->bytes);
36         } else {
37                 refprintf("args %jd\n", args->bytes);
38                 dassert(args->bytes == 0);
39         }
40 }
41
42
43 /*
44  * ptr.new()
45  *
46  */
47 static void donew(struct new_args *args, int islocked);
48
49 void
50 RuneSysCall_new_locked(struct new_args *args, void *rval __unused)
51 {
52         donew(args, 1);
53 }
54
55 void
56 RuneSysCall_new_unlocked(struct new_args *args, void *rval __unused)
57 {
58         donew(args, 0);
59 }
60
61
62 static
63 void
64 donew(struct new_args *args, int islocked)
65 {
66         runesize_t count = args->count;
67         runesize_t bytes;
68         Type *ptype = args->lvs.s_Type;
69         Type *type;
70         char *base;
71         PointerStor *ps;
72         RefStor *rs;
73
74 #if 1
75         refprintf("NEW args=%p ptype=%p %jd\n", args, ptype, ptype->ty_Bytes);
76         refprintf("NEWLVS %p %p %p\n", args->lvs.s_Addr, args->lvs.s_RefStor, args->lvs.s_Type);
77 #endif
78
79         switch(ptype->ty_Op) {
80         case TY_PTRTO:
81         case TY_REFTO:
82                 /*
83                  * Use the type in the pointer (even if the pointer is NULL
84                  * it should be properly typed).  This is the object target
85                  * type.
86                  *
87                  * XXX Allow the case where the pointer is completely zerod
88                  *     and take the reftype for that case ?
89                  */
90                 ps = (void *)args->lvs.s_Addr;
91                 type = ps->s_Type;
92                 dassert(type != NULL);
93 #if 1
94                 refprintf("NEWLVS-PTR %p %p %p %p %p\n", ps->s_Addr, ps->s_Beg, ps->s_End, ps->s_RefStor, ps->s_Type);
95 #endif
96                 if (ps->s_RefStor) {
97                         /*
98                          * Must use ptype to determine whether the storage
99                          * is locked or not.
100                          */
101                         refprintf("NEW: Putaway old RS=%p (assume locked storage)", ps->s_RefStor);
102                         if (islocked)
103                                 RuneRunTime_RSPut(ps->s_RefStor);
104                         else
105                                 RuneRunTime_RSRel(ps->s_RefStor);
106                 }
107                 ps->s_RefStor = NULL;
108                 break;
109         default:
110                 ps = NULL;
111                 type = NULL;
112                 dpanic("Rune new() called on non-pointer/non-reference ty=%d",
113                        ptype->ty_Op);
114         }
115
116         bytes = type->ty_Bytes * count;
117
118         dassert(bytes / count == type->ty_Bytes);
119
120         if (type->ty_SQFlags & SF_NOZERO &&
121             (type->ty_Flags & TF_HASLVPTR) == 0) {
122                 base = znalloc(bytes);
123         } else {
124                 base = zalloc(bytes);
125         }
126         ps->s_Addr = base;
127         ps->s_Beg = base;
128         ps->s_End = base + bytes;
129         ps->s_RefStor = NULL;
130         ps->s_Type = type;
131
132         rs = allocRefStor(type, RSOP_ZALLOC);
133         rs->rs_Count = count;
134         rs->rs_Base = base;
135
136         /* assume locked */
137         if (islocked)
138                 RuneRunTime_RSLock(rs);
139         ps->s_RefStor = rs;
140
141         /*
142          * Call run-time function to initialize the type if it needs it.
143          */
144         if (type->ty_Flags & (TF_HASLVPTR | TF_HASASS | TF_HASCONSTRUCT)) {
145                 while (count) {
146                         ((itype_func_t)type->ty_DynamicVector[0])(base, type);
147                         --count;
148                         base += type->ty_Bytes;
149                 }
150         }
151 }
152
153 /*
154  * Run-time heap and persistent store allocator.  This function will
155  * completely initialize a LValueStor given a storage declaration.  We
156  * need the decl and not just the type in order to determine whether the
157  * LValue represents HEAP or PERSISTent storage.
158  *
159  * Target storage is typically global so we assume unlocked semantics.
160  * Caller will lock the storage upon return if needed.
161  */
162 int
163 RuneRunTime_LVAlloc(LValueStor *lvs, Declaration *d)
164 {
165         Type *type = d->d_StorDecl.ed_Type;
166         RefStor *rs = NULL;
167         int res = 0;
168
169         if (d->d_ScopeFlags & SCOPE_HEAP) {
170                 rs = allocRefStor(type, RSOP_ZALLOC);
171
172                 if ((type->ty_SQFlags & SF_NOZERO) &&
173                     (type->ty_Flags & TF_HASLVPTR) == 0) {
174                         rs->rs_Base = znalloc(type->ty_Bytes);
175                 } else {
176                         rs->rs_Base = zalloc(type->ty_Bytes);
177                 }
178 #if 0
179                 fprintf(stderr, "LVAlloc: %jd (heap) rs=%p b=%p\n", type->ty_Bytes, rs, rs->rs_Base);
180 #endif
181         } else if (d->d_ScopeFlags & SCOPE_PERSIST) {
182                 struct stat st;
183                 const char *base;
184                 const char *prog;
185                 const char *id;
186                 int plen;
187                 char *path;
188                 int fd;
189
190                 id = d->d_Id;
191 #if 0
192                 fprintf(stderr, "LVAlloc: %s - %jd (persist)\n",
193                         id, type->ty_Bytes);
194 #endif
195
196                 /*
197                  * Default path is "$RUNEDATA/$prog/rune_%s.map".
198                  *
199                  * $prog is set to the project directive.  If there is no
200                  * project directive $prog is set to the base program name.
201                  *
202                  * If RUNEDATA exists we use $RUNEDATA/$prog/rune_*.map
203                  * else if uid == 0 we use /var/rune/$prog/rune_*.map
204                  * else if HOME we use $HOME/.rune/$prog/rune_*.map
205                  * else if USER we use /tmp/$USER/$prog/rune_*.map
206                  * else we use /tmp/$prog/rune_*.map
207                  */
208 #if 0
209                 prog = NULL;
210                 if (d->d_ScopeFlags & SCOPE_SHARED) {
211                         SemGroup *sg = d->d_MyGroup;
212
213                         prog = NULL;
214                         while (prog == NULL && sg) {
215                                 prog = sg->sg_Project;
216                                 sg = sg->sg_Parent;
217                         }
218                 }
219                 if (prog == NULL)
220 #endif
221                         prog = getprogname();
222
223                 if (strrchr(prog, '/'))
224                         prog = strrchr(prog, '/');
225                 if (strrchr(prog, '.'))
226                         plen = strrchr(prog, '.') - prog;
227                 else
228                         plen = (int)strlen(prog);
229                 if (plen > 2 && prog[plen-2] == '.')
230                         plen -= 2;
231
232                 base = getenv("RUNEDATA");
233                 if (base) {
234                         asprintf(&path, "%s/%*.*s/rune_%s.map",
235                                 base, plen, plen, prog, id);
236                 } else if (getuid() == 0) {
237                         asprintf(&path, "/var/rune/%*.*s/rune_%s.map",
238                                 plen, plen, prog, id);
239                 } else if ((base = getenv("HOME")) != NULL) {
240                         asprintf(&path, "%s/.rune/%*.*s/rune_%s.map",
241                                 base, plen, plen, prog, id);
242                 } else if ((base = getenv("USER")) != NULL) {
243                         asprintf(&path, "/tmp/%s/%*.*s/rune_%s.map",
244                                 base, plen, plen, prog, id);
245                 } else {
246                         asprintf(&path, "/tmp/%*.*s/rune_%s.map",
247                                 plen, plen, prog, id);
248                 }
249                 fprintf(stderr, "PATH %s\n", path);
250                 fd = open(path, O_RDWR|O_CREAT, 0666);
251                 if (fd < 0) {
252                         mkdirpath(path, 0);
253                         fd = open(path, O_RDWR|O_CREAT, 0666);
254                         if (fd < 0) {
255                                 fprintf(stderr, "Cannot open/create \"%s\"\n",
256                                         path);
257                                 exit(1);
258                         }
259                 }
260                 fstat(fd, &st);
261                 if (st.st_size == RSRESERVE + (off_t)type->ty_Bytes)
262                         res = 1;
263                 ftruncate(fd, RSRESERVE + type->ty_Bytes);
264                 dassert(RSRESERVE >= sizeof(*rs));
265                 rs = zalloc(sizeof(*rs));
266                 rs->rs_Base = mmap(NULL, RSRESERVE + type->ty_Bytes,
267                                    PROT_READ|PROT_WRITE,
268                                    MAP_SHARED|MAP_NOCORE|MAP_NOSYNC,
269                                    fd, 0);
270                 if ((void *)rs->rs_Base == MAP_FAILED)
271                         dpanic("persist storage mmap(\"%s\") failed\n", path);
272                 initRefStor(rs, type, RSOP_PERSIST);
273                 rs->rs_Base += RSRESERVE;
274
275                 if (res == 0)
276                         bzero(rs->rs_Base, type->ty_Bytes);
277                 close(fd);
278                 free(path);
279         } else {
280                 dpanic("Unsupported scope for lvalue declaration, "
281                        "(requires 'heap' or 'persist' only)");
282         }
283
284         /* assumes unlocked semantics */
285         /*RuneRunTime_RSLock(rs);*/
286
287         lvs->s_Addr = rs->rs_Base;
288         lvs->s_RefStor = rs;
289         lvs->s_Type = type;
290
291         /*
292          * Call run-time function to initialize the type if it needs it.
293          *
294          * XXX if already initialized we still want to call the constructors.
295          */
296         if (type->ty_Flags & (TF_HASLVPTR | TF_HASASS | TF_HASCONSTRUCT)) {
297                 if (res == 0) {
298                         ((itype_func_t)
299                          type->ty_DynamicVector[0])(lvs->s_Addr, type);
300                 }
301         }
302
303         return res;
304 }
305
306 struct exit_args {
307         int32_t         code;
308 };
309
310 void
311 RuneSysCall_exit(struct exit_args *args, void *rval __unused)
312 {
313         exit(args->code);
314 }
315
316
317 struct abort_args {
318         int             dummy;
319 };
320
321 void
322 RuneSysCall_abort(struct abort_args *args __unused, void *rval __unused)
323 {
324         dpanic("");
325 }
326
327
328 struct getenv_args {
329         PointerStor     name;
330 };
331
332 void
333 RuneSysCall_getenv(struct getenv_args *args, PointerStor *resp)
334 {
335         RefStor *rs;
336         const char *str;
337         char *base;
338         size_t len;
339
340         if ((rs = resp->s_RefStor) != NULL) {
341                 RuneRunTime_RSRel(rs);
342                 resp->s_Addr = NULL;
343                 resp->s_Beg = NULL;
344                 resp->s_End = NULL;
345                 resp->s_RefStor = NULL;
346         }
347         STRBOUNDSCHECK(&args->name, PATH_MAX);
348         str = getenv(args->name.s_Addr);
349         if (str) {
350                 len = strlen(str) + 1;
351                 base = zalloc(len);
352                 bcopy(str, base, len);
353                 rs = allocRefStor(&CharPtrType, RSOP_ZALLOC);
354                 rs->rs_Count = len;
355                 rs->rs_Base = base;
356                 rs->rs_Type = &UInt8Type;
357
358                 resp->s_Addr = base;
359                 resp->s_Beg = base;
360                 resp->s_End = base + len;
361                 resp->s_RefStor = rs;
362                 resp->s_Type = &CharPtrType;
363         }
364 }
365
366
367 struct setenv_args {
368         PointerStor     name;
369         PointerStor     value;
370 };
371
372 void
373 RuneSysCall_setenv(struct setenv_args *args, void *resp)
374 {
375         STRBOUNDSCHECK(&args->name, 0x3FFFFFFF);
376         STRBOUNDSCHECK(&args->value, 0x3FFFFFFF);
377         if (setenv(args->name.s_Addr, args->value.s_Addr, 1) < 0) {
378                 dpanic("setenv(\"%s\", \"%s\") failed",
379                         args->name.s_Addr, args->value.s_Addr);
380         }
381 }
382
383 struct unsetenv_args {
384         PointerStor     name;
385 };
386
387 void
388 RuneSysCall_unsetenv(struct unsetenv_args *args, int *resp)
389 {
390         STRBOUNDSCHECK(&args->name, PATH_MAX);
391         if (unsetenv(args->name.s_Addr) < 0) {
392                 *resp = -1;
393         } else {
394                 *resp = 0;
395         }
396 }