From b2cfc4e2e71d0f0a5113ddfbd93c8285cc4d74e4 Mon Sep 17 00:00:00 2001 From: rsc Date: Tue, 30 Sep 2003 17:47:41 +0000 Subject: Initial revision --- src/lib9/LICENSE | 258 ++++++++++++++++++++++++++ src/lib9/Make.Darwin-PowerMacintosh | 6 + src/lib9/Make.FreeBSD-386 | 7 + src/lib9/Make.HP-UX-9000 | 6 + src/lib9/Make.Linux-386 | 7 + src/lib9/Make.NetBSD-386 | 7 + src/lib9/Make.OSF1-alpha | 6 + src/lib9/Make.SunOS-sun4u | 2 + src/lib9/Make.SunOS-sun4u-cc | 6 + src/lib9/Make.SunOS-sun4u-gcc | 6 + src/lib9/Makefile | 120 ++++++++++++ src/lib9/Makefile.MID | 49 +++++ src/lib9/_exits.c | 9 + src/lib9/argv0.c | 4 + src/lib9/await.c | 105 +++++++++++ src/lib9/encodefmt.c | 69 +++++++ src/lib9/errstr.c | 68 +++++++ src/lib9/exits.c | 10 + src/lib9/ffork-FreeBSD.c | 33 ++++ src/lib9/ffork-Linux.c | 39 ++++ src/lib9/getcallerpc-386.c | 7 + src/lib9/getfields.c | 36 ++++ src/lib9/lib9.h | 246 ++++++++++++++++++++++++ src/lib9/lock.c | 54 ++++++ src/lib9/malloctag.c | 15 ++ src/lib9/mallocz.c | 14 ++ src/lib9/mkfile | 2 + src/lib9/nrand.c | 17 ++ src/lib9/qlock.c | 360 ++++++++++++++++++++++++++++++++++++ src/lib9/rand.c | 89 +++++++++ src/lib9/readn.c | 21 +++ src/lib9/rendez.c | 180 ++++++++++++++++++ src/lib9/strecpy.c | 16 ++ src/lib9/sysfatal.c | 20 ++ src/lib9/tas-386.s | 6 + src/lib9/test.c | 8 + src/lib9/testfork.c | 21 +++ src/lib9/tokenize.c | 106 +++++++++++ src/lib9/u16.c | 52 ++++++ src/lib9/u32.c | 109 +++++++++++ src/lib9/u64.c | 126 +++++++++++++ src/lib9/wait.c | 30 +++ src/lib9/werrstr.c | 13 ++ 43 files changed, 2365 insertions(+) create mode 100644 src/lib9/LICENSE create mode 100644 src/lib9/Make.Darwin-PowerMacintosh create mode 100644 src/lib9/Make.FreeBSD-386 create mode 100644 src/lib9/Make.HP-UX-9000 create mode 100644 src/lib9/Make.Linux-386 create mode 100644 src/lib9/Make.NetBSD-386 create mode 100644 src/lib9/Make.OSF1-alpha create mode 100644 src/lib9/Make.SunOS-sun4u create mode 100644 src/lib9/Make.SunOS-sun4u-cc create mode 100644 src/lib9/Make.SunOS-sun4u-gcc create mode 100644 src/lib9/Makefile create mode 100644 src/lib9/Makefile.MID create mode 100644 src/lib9/_exits.c create mode 100644 src/lib9/argv0.c create mode 100644 src/lib9/await.c create mode 100644 src/lib9/encodefmt.c create mode 100644 src/lib9/errstr.c create mode 100644 src/lib9/exits.c create mode 100644 src/lib9/ffork-FreeBSD.c create mode 100644 src/lib9/ffork-Linux.c create mode 100644 src/lib9/getcallerpc-386.c create mode 100644 src/lib9/getfields.c create mode 100644 src/lib9/lib9.h create mode 100644 src/lib9/lock.c create mode 100644 src/lib9/malloctag.c create mode 100644 src/lib9/mallocz.c create mode 100644 src/lib9/mkfile create mode 100644 src/lib9/nrand.c create mode 100644 src/lib9/qlock.c create mode 100644 src/lib9/rand.c create mode 100644 src/lib9/readn.c create mode 100644 src/lib9/rendez.c create mode 100644 src/lib9/strecpy.c create mode 100644 src/lib9/sysfatal.c create mode 100644 src/lib9/tas-386.s create mode 100644 src/lib9/test.c create mode 100644 src/lib9/testfork.c create mode 100644 src/lib9/tokenize.c create mode 100644 src/lib9/u16.c create mode 100644 src/lib9/u32.c create mode 100644 src/lib9/u64.c create mode 100644 src/lib9/wait.c create mode 100644 src/lib9/werrstr.c (limited to 'src/lib9') diff --git a/src/lib9/LICENSE b/src/lib9/LICENSE new file mode 100644 index 00000000..a5d7d87d --- /dev/null +++ b/src/lib9/LICENSE @@ -0,0 +1,258 @@ +The Plan 9 software is provided under the terms of the +Lucent Public License, Version 1.02, reproduced below, +with the following exceptions: + +1. No right is granted to create derivative works of or + to redistribute (other than with the Plan 9 Operating System) + the screen imprinter fonts identified in subdirectory + /lib/font/bit/lucida and printer fonts (Lucida Sans Unicode, Lucida + Sans Italic, Lucida Sans Demibold, Lucida Typewriter, Lucida Sans + Typewriter83), identified in subdirectory /sys/lib/postscript/font. + These directories contain material copyrights by B&H Inc. and Y&Y Inc. + +2. The printer fonts identified in subdirectory /sys/lib/ghostscript/font + are subject to the GNU GPL, reproduced in the file /LICENSE.gpl. + +3. The ghostscript program in the subdirectory /sys/src/cmd/gs is + covered by the Aladdin Free Public License, reproduced in the file + /LICENSE.afpl. + +=================================================================== + +Lucent Public License Version 1.02 + +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS PUBLIC +LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE +PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + +1. DEFINITIONS + +"Contribution" means: + + a. in the case of Lucent Technologies Inc. ("LUCENT"), the Original + Program, and + b. in the case of each Contributor, + + i. changes to the Program, and + ii. additions to the Program; + + where such changes and/or additions to the Program were added to the + Program by such Contributor itself or anyone acting on such + Contributor's behalf, and the Contributor explicitly consents, in + accordance with Section 3C, to characterization of the changes and/or + additions as Contributions. + +"Contributor" means LUCENT and any other entity that has Contributed a +Contribution to the Program. + +"Distributor" means a Recipient that distributes the Program, +modifications to the Program, or any part thereof. + +"Licensed Patents" mean patent claims licensable by a Contributor +which are necessarily infringed by the use or sale of its Contribution +alone or when combined with the Program. + +"Original Program" means the original version of the software +accompanying this Agreement as released by LUCENT, including source +code, object code and documentation, if any. + +"Program" means the Original Program and Contributions or any part +thereof + +"Recipient" means anyone who receives the Program under this +Agreement, including all Contributors. + +2. GRANT OF RIGHTS + + a. Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free copyright + license to reproduce, prepare derivative works of, publicly display, + publicly perform, distribute and sublicense the Contribution of such + Contributor, if any, and such derivative works, in source code and + object code form. + + b. Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free patent + license under Licensed Patents to make, use, sell, offer to sell, + import and otherwise transfer the Contribution of such Contributor, if + any, in source code and object code form. The patent license granted + by a Contributor shall also apply to the combination of the + Contribution of that Contributor and the Program if, at the time the + Contribution is added by the Contributor, such addition of the + Contribution causes such combination to be covered by the Licensed + Patents. The patent license granted by a Contributor shall not apply + to (i) any other combinations which include the Contribution, nor to + (ii) Contributions of other Contributors. No hardware per se is + licensed hereunder. + + c. Recipient understands that although each Contributor grants the + licenses to its Contributions set forth herein, no assurances are + provided by any Contributor that the Program does not infringe the + patent or other intellectual property rights of any other entity. Each + Contributor disclaims any liability to Recipient for claims brought by + any other entity based on infringement of intellectual property rights + or otherwise. As a condition to exercising the rights and licenses + granted hereunder, each Recipient hereby assumes sole responsibility + to secure any other intellectual property rights needed, if any. For + example, if a third party patent license is required to allow + Recipient to distribute the Program, it is Recipient's responsibility + to acquire that license before distributing the Program. + + d. Each Contributor represents that to its knowledge it has sufficient + copyright rights in its Contribution, if any, to grant the copyright + license set forth in this Agreement. + +3. REQUIREMENTS + +A. Distributor may choose to distribute the Program in any form under +this Agreement or under its own license agreement, provided that: + + a. it complies with the terms and conditions of this Agreement; + + b. if the Program is distributed in source code or other tangible + form, a copy of this Agreement or Distributor's own license agreement + is included with each copy of the Program; and + + c. if distributed under Distributor's own license agreement, such + license agreement: + + i. effectively disclaims on behalf of all Contributors all warranties + and conditions, express and implied, including warranties or + conditions of title and non-infringement, and implied warranties or + conditions of merchantability and fitness for a particular purpose; + ii. effectively excludes on behalf of all Contributors all liability + for damages, including direct, indirect, special, incidental and + consequential damages, such as lost profits; and + iii. states that any provisions which differ from this Agreement are + offered by that Contributor alone and not by any other party. + +B. Each Distributor must include the following in a conspicuous + location in the Program: + + Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights + Reserved. + +C. In addition, each Contributor must identify itself as the +originator of its Contribution in a manner that reasonably allows +subsequent Recipients to identify the originator of the Contribution. +Also, each Contributor must agree that the additions and/or changes +are intended to be a Contribution. Once a Contribution is contributed, +it may not thereafter be revoked. + +4. COMMERCIAL DISTRIBUTION + +Commercial distributors of software may accept certain +responsibilities with respect to end users, business partners and the +like. While this license is intended to facilitate the commercial use +of the Program, the Distributor who includes the Program in a +commercial product offering should do so in a manner which does not +create potential liability for Contributors. Therefore, if a +Distributor includes the Program in a commercial product offering, +such Distributor ("Commercial Distributor") hereby agrees to defend +and indemnify every Contributor ("Indemnified Contributor") against +any losses, damages and costs (collectively"Losses") arising from +claims, lawsuits and other legal actions brought by a third party +against the Indemnified Contributor to the extent caused by the acts +or omissions of such Commercial Distributor in connection with its +distribution of the Program in a commercial product offering. The +obligations in this section do not apply to any claims or Losses +relating to any actual or alleged intellectual property infringement. +In order to qualify, an Indemnified Contributor must: a) promptly +notify the Commercial Distributor in writing of such claim, and b) +allow the Commercial Distributor to control, and cooperate with the +Commercial Distributor in, the defense and any related settlement +negotiations. The Indemnified Contributor may participate in any such +claim at its own expense. + +For example, a Distributor might include the Program in a commercial +product offering, Product X. That Distributor is then a Commercial +Distributor. If that Commercial Distributor then makes performance +claims, or offers warranties related to Product X, those performance +claims and warranties are such Commercial Distributor's responsibility +alone. Under this section, the Commercial Distributor would have to +defend claims against the Contributors related to those performance +claims and warranties, and if a court requires any Contributor to pay +any damages as a result, the Commercial Distributor must pay those +damages. + +5. NO WARRANTY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS +PROVIDED ON AN"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY +WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY +OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely +responsible for determining the appropriateness of using and +distributing the Program and assumes all risks associated with its +exercise of rights under this Agreement, including but not limited to +the risks and costs of program errors, compliance with applicable +laws, damage to or loss of data, programs or equipment, and +unavailability or interruption of operations. + +6. DISCLAIMER OF LIABILITY + +EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR +ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING +WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR +DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED +HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. EXPORT CONTROL + +Recipient agrees that Recipient alone is responsible for compliance +with the United States export administration regulations (and the +export control laws and regulation of any other countries). + +8. GENERAL + +If any provision of this Agreement is invalid or unenforceable under +applicable law, it shall not affect the validity or enforceability of +the remainder of the terms of this Agreement, and without further +action by the parties hereto, such provision shall be reformed to the +minimum extent necessary to make such provision valid and enforceable. + +If Recipient institutes patent litigation against a Contributor with +respect to a patent applicable to software (including a cross-claim or +counterclaim in a lawsuit), then any patent licenses granted by that +Contributor to such Recipient under this Agreement shall terminate as +of the date such litigation is filed. In addition, if Recipient +institutes patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Program +itself (excluding combinations of the Program with other software or +hardware) infringes such Recipient's patent(s), then such Recipient's +rights granted under Section 2(b) shall terminate as of the date such +litigation is filed. + +All Recipient's rights under this Agreement shall terminate if it +fails to comply with any of the material terms or conditions of this +Agreement and does not cure such failure in a reasonable period of +time after becoming aware of such noncompliance. If all Recipient's +rights under this Agreement terminate, Recipient agrees to cease use +and distribution of the Program as soon as reasonably practicable. +However, Recipient's obligations under this Agreement and any licenses +granted by Recipient relating to the Program shall continue and +survive. + +LUCENT may publish new versions (including revisions) of this +Agreement from time to time. Each new version of the Agreement will be +given a distinguishing version number. The Program (including +Contributions) may always be distributed subject to the version of the +Agreement under which it was received. In addition, after a new +version of the Agreement is published, Contributor may elect to +distribute the Program (including its Contributions) under the new +version. No one other than LUCENT has the right to modify this +Agreement. Except as expressly stated in Sections 2(a) and 2(b) above, +Recipient receives no rights or licenses to the intellectual property +of any Contributor under this Agreement, whether expressly, by +implication, estoppel or otherwise. All rights in the Program not +expressly granted under this Agreement are reserved. + +This Agreement is governed by the laws of the State of New York and +the intellectual property laws of the United States of America. No +party to this Agreement will bring a legal action under this Agreement +more than one year after the cause of action arose. Each party waives +its rights to a jury trial in any resulting litigation. + diff --git a/src/lib9/Make.Darwin-PowerMacintosh b/src/lib9/Make.Darwin-PowerMacintosh new file mode 100644 index 00000000..14b8d4e7 --- /dev/null +++ b/src/lib9/Make.Darwin-PowerMacintosh @@ -0,0 +1,6 @@ +CC=gcc +CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I. -I${PREFIX}/include +O=o +AR=ar +ARFLAGS=rvc +NAN=nan64.$O diff --git a/src/lib9/Make.FreeBSD-386 b/src/lib9/Make.FreeBSD-386 new file mode 100644 index 00000000..087ed3ab --- /dev/null +++ b/src/lib9/Make.FreeBSD-386 @@ -0,0 +1,7 @@ +CC=gcc +CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I. -I$(PREFIX)/include +O=o +AR=ar +ARFLAGS=rvc +NAN=nan64.$O # default, can be overriden by Make.$(SYSNAME) +NAN=nan64.$O diff --git a/src/lib9/Make.HP-UX-9000 b/src/lib9/Make.HP-UX-9000 new file mode 100644 index 00000000..edbdc111 --- /dev/null +++ b/src/lib9/Make.HP-UX-9000 @@ -0,0 +1,6 @@ +CC=cc +CFLAGS=-O -c -Ae -I. +O=o +AR=ar +ARFLAGS=rvc +NAN=nan64.$O diff --git a/src/lib9/Make.Linux-386 b/src/lib9/Make.Linux-386 new file mode 100644 index 00000000..74b0252c --- /dev/null +++ b/src/lib9/Make.Linux-386 @@ -0,0 +1,7 @@ +CC=gcc +CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I. +O=o +AR=ar +ARFLAGS=rvc +NAN=nan64.$O # default, can be overriden by Make.$(SYSNAME) +NAN=nan64.$O diff --git a/src/lib9/Make.NetBSD-386 b/src/lib9/Make.NetBSD-386 new file mode 100644 index 00000000..087ed3ab --- /dev/null +++ b/src/lib9/Make.NetBSD-386 @@ -0,0 +1,7 @@ +CC=gcc +CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I. -I$(PREFIX)/include +O=o +AR=ar +ARFLAGS=rvc +NAN=nan64.$O # default, can be overriden by Make.$(SYSNAME) +NAN=nan64.$O diff --git a/src/lib9/Make.OSF1-alpha b/src/lib9/Make.OSF1-alpha new file mode 100644 index 00000000..3d45279b --- /dev/null +++ b/src/lib9/Make.OSF1-alpha @@ -0,0 +1,6 @@ +CC=cc +CFLAGS+=-g -c -I. +O=o +AR=ar +ARFLAGS=rvc +NAN=nan64.$O diff --git a/src/lib9/Make.SunOS-sun4u b/src/lib9/Make.SunOS-sun4u new file mode 100644 index 00000000..c5fe67b8 --- /dev/null +++ b/src/lib9/Make.SunOS-sun4u @@ -0,0 +1,2 @@ +include Make.SunOS-sun4u-$(CC) +NAN=nan64.$O diff --git a/src/lib9/Make.SunOS-sun4u-cc b/src/lib9/Make.SunOS-sun4u-cc new file mode 100644 index 00000000..829301de --- /dev/null +++ b/src/lib9/Make.SunOS-sun4u-cc @@ -0,0 +1,6 @@ +CC=cc +CFLAGS+=-g -c -I. -O +O=o +AR=ar +ARFLAGS=rvc +NAN=nan64.$O diff --git a/src/lib9/Make.SunOS-sun4u-gcc b/src/lib9/Make.SunOS-sun4u-gcc new file mode 100644 index 00000000..5c415948 --- /dev/null +++ b/src/lib9/Make.SunOS-sun4u-gcc @@ -0,0 +1,6 @@ +CC=gcc +CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c +O=o +AR=ar +ARFLAGS=rvc +NAN=nan64.$O diff --git a/src/lib9/Makefile b/src/lib9/Makefile new file mode 100644 index 00000000..595db787 --- /dev/null +++ b/src/lib9/Makefile @@ -0,0 +1,120 @@ + +# this works in gnu make +SYSNAME:=${shell uname} +OBJTYPE:=${shell uname -m | sed 's;i.86;386;; s;/.*;;; s; ;;g'} + +# this works in bsd make +SYSNAME!=uname +OBJTYPE!=uname -m | sed 's;i.86;386;; s;/.*;;; s; ;;g' + +# the gnu rules will mess up bsd but not vice versa, +# hence the gnu rules come first. + +include Make.$(SYSNAME)-$(OBJTYPE) + +PREFIX=/usr/local + +NUKEFILES= + +TGZFILES= + +LIB=lib9.a +VERSION=2.0 +PORTPLACE=devel/lib9 +NAME=lib9 + +OFILES=\ + _exits.$O\ + argv0.$O\ + await.$O\ + encodefmt.$O\ + errstr.$O\ + exits.$O\ + ffork-$(SYSNAME).$O\ + getcallerpc-$(OBJTYPE).$O\ + getfields.$O\ + lock.$O\ + malloctag.$O\ + mallocz.$O\ + nrand.$O\ + qlock.$O\ + readn.$O\ + rendez.$O\ + strecpy.$O\ + sysfatal.$O\ + tas-$(OBJTYPE).$O\ + tokenize.$O\ + u16.$O\ + u32.$O\ + u64.$O\ + wait.$O\ + werrstr.$O\ + +HFILES=\ + lib9.h\ + +all: $(LIB) + +install: $(LIB) + test -d $(PREFIX)/man/man3 || mkdir $(PREFIX)/man/man3 + # install -m 0644 lib9.3 $(PREFIX)/man/man3/lib9.3 + install -m 0644 lib9.h $(PREFIX)/include/lib9.h + install -m 0644 $(LIB) $(PREFIX)/lib/$(LIB) + +test: $(LIB) test.$O + $(CC) -o test test.$O $(LIB) -L$(PREFIX)/lib -lfmt -lutf + +testfork: $(LIB) testfork.$O + $(CC) -o testfork testfork.$O $(LIB) -L$(PREFIX)/lib -lfmt -lutf + +$(LIB): $(OFILES) + $(AR) $(ARFLAGS) $(LIB) $(OFILES) + +NUKEFILES+=$(LIB) +.c.$O: + $(CC) $(CFLAGS) -I$(PREFIX)/include $*.c + +%.$O: %.c + $(CC) $(CFLAGS) -I$(PREFIX)/include $*.c + + +$(OFILES): $(HFILES) + +tgz: + rm -rf $(NAME)-$(VERSION) + mkdir $(NAME)-$(VERSION) + cp Makefile Make.* README LICENSE NOTICE *.[ch137] rpm.spec bundle.ports $(TGZFILES) $(NAME)-$(VERSION) + tar cf - $(NAME)-$(VERSION) | gzip >$(NAME)-$(VERSION).tgz + rm -rf $(NAME)-$(VERSION) + +clean: + rm -f $(OFILES) $(LIB) + +nuke: + rm -f $(OFILES) *.tgz *.rpm $(NUKEFILES) + +rpm: + make tgz + cp $(NAME)-$(VERSION).tgz /usr/src/RPM/SOURCES + rpm -ba rpm.spec + cp /usr/src/RPM/SRPMS/$(NAME)-$(VERSION)-1.src.rpm . + cp /usr/src/RPM/RPMS/i586/$(NAME)-$(VERSION)-1.i586.rpm . + scp *.rpm rsc@amsterdam.lcs.mit.edu:public_html/software + +PORTDIR=/usr/ports/$(PORTPLACE) + +ports: + make tgz + rm -rf $(PORTDIR) + mkdir $(PORTDIR) + cp $(NAME)-$(VERSION).tgz /usr/ports/distfiles + cat bundle.ports | (cd $(PORTDIR) && awk '$$1=="---" && $$3=="---" { ofile=$$2; next} {if(ofile) print >ofile}') + (cd $(PORTDIR); make makesum) + (cd $(PORTDIR); make) + (cd $(PORTDIR); /usr/local/bin/portlint) + rm -rf $(PORTDIR)/work + shar `find $(PORTDIR)` > ports.shar + (cd $(PORTDIR); tar cf - *) | gzip >$(NAME)-$(VERSION)-ports.tgz + scp *.tgz rsc@amsterdam.lcs.mit.edu:public_html/software + +.phony: all clean nuke install tgz rpm ports diff --git a/src/lib9/Makefile.MID b/src/lib9/Makefile.MID new file mode 100644 index 00000000..8b3584cb --- /dev/null +++ b/src/lib9/Makefile.MID @@ -0,0 +1,49 @@ +LIB=lib9.a +VERSION=2.0 +PORTPLACE=devel/lib9 +NAME=lib9 + +OFILES=\ + _exits.$O\ + argv0.$O\ + await.$O\ + encodefmt.$O\ + errstr.$O\ + exits.$O\ + ffork-$(SYSNAME).$O\ + getcallerpc-$(OBJTYPE).$O\ + getfields.$O\ + lock.$O\ + malloctag.$O\ + mallocz.$O\ + nrand.$O\ + qlock.$O\ + readn.$O\ + rendez.$O\ + strecpy.$O\ + sysfatal.$O\ + tas-$(OBJTYPE).$O\ + tokenize.$O\ + u16.$O\ + u32.$O\ + u64.$O\ + wait.$O\ + werrstr.$O\ + +HFILES=\ + lib9.h\ + +all: $(LIB) + +install: $(LIB) + test -d $(PREFIX)/man/man3 || mkdir $(PREFIX)/man/man3 + # install -m 0644 lib9.3 $(PREFIX)/man/man3/lib9.3 + install -m 0644 lib9.h $(PREFIX)/include/lib9.h + install -m 0644 $(LIB) $(PREFIX)/lib/$(LIB) + +test: $(LIB) test.$O + $(CC) -o test test.$O $(LIB) -L$(PREFIX)/lib -lfmt -lutf + +testfork: $(LIB) testfork.$O + $(CC) -o testfork testfork.$O $(LIB) -L$(PREFIX)/lib -lfmt -lutf + diff --git a/src/lib9/_exits.c b/src/lib9/_exits.c new file mode 100644 index 00000000..35ff4e67 --- /dev/null +++ b/src/lib9/_exits.c @@ -0,0 +1,9 @@ +#include + +void +_exits(char *s) +{ + if(s && *s) + _exit(1); + _exit(0); +} diff --git a/src/lib9/argv0.c b/src/lib9/argv0.c new file mode 100644 index 00000000..2c846f4d --- /dev/null +++ b/src/lib9/argv0.c @@ -0,0 +1,4 @@ +#include + +char *argv0; + diff --git a/src/lib9/await.c b/src/lib9/await.c new file mode 100644 index 00000000..9df7faa5 --- /dev/null +++ b/src/lib9/await.c @@ -0,0 +1,105 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +static struct { + int sig; + char *str; +} tab[] = { + SIGHUP, "hangup", + SIGINT, "interrupt", + SIGQUIT, "quit", + SIGILL, "sys: trap: illegal instruction", + SIGTRAP, "sys: trace trap", + SIGABRT, "sys: abort", +#ifdef SIGEMT + SIGEMT, "sys: emulate instruction executed", +#endif + SIGFPE, "sys: fp: trap", + SIGKILL, "sys: kill", + SIGBUS, "sys: bus error", + SIGSEGV, "sys: segmentation violation", + SIGALRM, "alarm", + SIGTERM, "kill", + SIGURG, "sys: urgent condition on socket", + SIGSTOP, "sys: stop", + SIGTSTP, "sys: tstp", + SIGCONT, "sys: cont", + SIGCHLD, "sys: child", + SIGTTIN, "sys: ttin", + SIGTTOU, "sys: ttou", + SIGIO, "sys: i/o possible on fd", + SIGXCPU, "sys: cpu time limit exceeded", + SIGXFSZ, "sys: file size limit exceeded", + SIGVTALRM, "sys: virtual time alarm", + SIGPROF, "sys: profiling timer alarm", + SIGWINCH, "sys: window size change", +#ifdef SIGINFO + SIGINFO, "sys: status request", +#endif + SIGUSR1, "sys: usr1", + SIGUSR2, "sys: usr2", +}; + +static char* +_p9sigstr(int sig, char *tmp) +{ + int i; + + for(i=0; i + +int +encodefmt(Fmt *f) +{ + char *out; + char *buf; + int len; + int ilen; + int rv; + uchar *b; + char obuf[64]; // rsc optimization + + if(!(f->flags&FmtPrec) || f->prec < 1) + goto error; + + b = va_arg(f->args, uchar*); + + ilen = f->prec; + f->prec = 0; + f->flags &= ~FmtPrec; + switch(f->r){ + case '<': + len = (8*ilen+4)/5 + 3; + break; + case '[': + len = (8*ilen+5)/6 + 4; + break; + case 'H': + len = 2*ilen + 1; + break; + default: + goto error; + } + + if(len > sizeof(obuf)){ + buf = malloc(len); + if(buf == nil) + goto error; + } else + buf = obuf; + + // convert + out = buf; + switch(f->r){ + case '<': + rv = enc32(out, len, b, ilen); + break; + case '[': + rv = enc64(out, len, b, ilen); + break; + case 'H': + rv = enc16(out, len, b, ilen); + break; + default: + rv = -1; + break; + } + if(rv < 0) + goto error; + + fmtstrcpy(f, buf); + if(buf != obuf) + free(buf); + return 0; + +error: + return fmtstrcpy(f, ""); +} diff --git a/src/lib9/errstr.c b/src/lib9/errstr.c new file mode 100644 index 00000000..e576b12b --- /dev/null +++ b/src/lib9/errstr.c @@ -0,0 +1,68 @@ +/* + * We assume there's only one error buffer for the whole system. + * If you use ffork, you need to provide a _syserrstr. Since most + * people will use libthread (which provides a _syserrstr), this is + * okay. + */ + +#include +#include +#include + +enum +{ + EPLAN9 = 0x19283745, +}; + +char *(*_syserrstr)(void); +static char xsyserr[ERRMAX]; +static char* +getsyserr(void) +{ + char *s; + + s = nil; + if(_syserrstr) + s = (*_syserrstr)(); + if(s == nil) + s = xsyserr; + return s; +} + +int +errstr(char *err, uint n) +{ + char tmp[ERRMAX]; + char *syserr; + + syserr = getsyserr(); + if(errno != EPLAN9) + strcpy(syserr, strerror(errno)); + + strecpy(tmp, tmp+ERRMAX, syserr); + strecpy(syserr, syserr+ERRMAX, err); + strecpy(err, err+n, tmp); + errno = EPLAN9; + return 0; +} + +void +rerrstr(char *err, uint n) +{ + char *syserr; + + syserr = getsyserr(); + if(errno != EPLAN9) + strcpy(syserr, strerror(errno)); + strecpy(err, err+n, syserr); +} + +/* replaces __errfmt in libfmt */ + +int +__errfmt(Fmt *f) +{ + if(errno == EPLAN9) + return fmtstrcpy(f, getsyserr()); + return fmtstrcpy(f, strerror(errno)); +} diff --git a/src/lib9/exits.c b/src/lib9/exits.c new file mode 100644 index 00000000..a449f68e --- /dev/null +++ b/src/lib9/exits.c @@ -0,0 +1,10 @@ +#include + +void +exits(char *s) +{ + if(s && *s) + exit(1); + exit(0); +} + diff --git a/src/lib9/ffork-FreeBSD.c b/src/lib9/ffork-FreeBSD.c new file mode 100644 index 00000000..a7c82e64 --- /dev/null +++ b/src/lib9/ffork-FreeBSD.c @@ -0,0 +1,33 @@ +#include + +extern int __isthreaded; +int +ffork(int flags, void(*fn)(void*), void *arg) +{ + void *p; + + __isthreaded = 1; + p = malloc(16384); + if(p == nil) + return -1; + memset(p, 0xFE, 16384); + return rfork_thread(RFPROC|flags, (char*)p+16000, (int(*)(void*))fn, arg); +} + +/* + * For FreeBSD libc. + */ + +typedef struct { + volatile long access_lock; + volatile long lock_owner; + volatile char *fname; + volatile int lineno; +} spinlock_t; + +void +_spinlock(spinlock_t *lk) +{ + lock((Lock*)&lk->access_lock); +} + diff --git a/src/lib9/ffork-Linux.c b/src/lib9/ffork-Linux.c new file mode 100644 index 00000000..aad80041 --- /dev/null +++ b/src/lib9/ffork-Linux.c @@ -0,0 +1,39 @@ +#include +#include +#include + +int fforkstacksize = 16384; + +int +ffork(int flags, void (*fn)(void*), void *arg) +{ + char *p; + int cloneflag, pid; + + p = malloc(fforkstacksize); + if(p == nil) + return -1; + cloneflag = 0; + flags &= ~RFPROC; + if(flags&RFMEM){ + cloneflag |= CLONE_VM; + flags &= ~RFMEM; + } + if(!(flags&RFFDG)) + cloneflag |= CLONE_FILES; + else + flags &= ~RFFDG; + if(!(flags&RFNOWAIT)) + cloneflag |= SIGCHLD; + else + flags &= ~RFNOWAIT; + if(flags){ + fprint(2, "unknown rfork flags %x\n", flags); + return -1; + } + pid = clone((int(*)(void*))fn, p+fforkstacksize-16, cloneflag, arg); + if(pid < 0) + free(p); + return pid; +} + diff --git a/src/lib9/getcallerpc-386.c b/src/lib9/getcallerpc-386.c new file mode 100644 index 00000000..1367370e --- /dev/null +++ b/src/lib9/getcallerpc-386.c @@ -0,0 +1,7 @@ +#include + +ulong +getcallerpc(void *x) +{ + return (((ulong*)(x))[-1]); +} diff --git a/src/lib9/getfields.c b/src/lib9/getfields.c new file mode 100644 index 00000000..79f7abad --- /dev/null +++ b/src/lib9/getfields.c @@ -0,0 +1,36 @@ +#include + +int +getfields(char *str, char **args, int max, int mflag, char *set) +{ + Rune r; + int nr, intok, narg; + + if(max <= 0) + return 0; + + narg = 0; + args[narg] = str; + if(!mflag) + narg++; + intok = 0; + for(;; str += nr) { + nr = chartorune(&r, str); + if(r == 0) + break; + if(utfrune(set, r)) { + if(narg >= max) + break; + *str = 0; + intok = 0; + args[narg] = str + nr; + if(!mflag) + narg++; + } else { + if(!intok && mflag) + narg++; + intok = 1; + } + } + return narg; +} diff --git a/src/lib9/lib9.h b/src/lib9/lib9.h new file mode 100644 index 00000000..bb7e5404 --- /dev/null +++ b/src/lib9/lib9.h @@ -0,0 +1,246 @@ +/* + * Lib9 is miscellany from the Plan 9 C library that doesn't + * fit into libutf or into libfmt, but is still missing from traditional + * Unix C libraries. + */ +#ifndef _LIB9H_ +#define _LIB9H_ 1 + +#if defined(__cplusplus) +extern "C" { +#endif + + +#include +#include +#include +#include +#include +#include + +#ifndef _FMTH_ +# include +#endif + +#define nil ((void*)0) +#define nelem(x) (sizeof(x)/sizeof((x)[0])) + +#define _NEEDUCHAR 1 +#define _NEEDUSHORT 1 +#define _NEEDUINT 1 +#define _NEEDULONG 1 + +#if defined(__linux__) +# include +# if defined(__USE_MISC) +# undef _NEEDUSHORT +# undef _NEEDUINT +# undef _NEEDULONG +# endif +#endif +#if defined(__FreeBSD__) +# include +# if !defined(_POSIX_SOURCE) +# undef _NEEDUSHORT +# undef _NEEDUINT +# endif +#endif + +typedef signed char schar; +typedef unsigned int u32int; +#ifdef _NEEDUCHAR + typedef unsigned char uchar; +#endif +#ifdef _NEEDUSHORT + typedef unsigned short ushort; +#endif +#ifdef _NEEDUINT + typedef unsigned int uint; +#endif +#ifdef _NEEDULONG + typedef unsigned long ulong; +#endif +typedef unsigned long long uvlong; +typedef long long vlong; + +/* rfork to create new process running fn(arg) */ + +#if defined(__FreeBSD__) +#undef RFFDG +#undef RFNOTEG +#undef RFPROC +#undef RFMEM +#undef RFNOWAIT +#undef RFCFDG +#endif + +enum +{ +/* RFNAMEG = (1<<0), */ +/* RFENVG = (1<<1), */ + RFFDG = (1<<2), + RFNOTEG = (1<<3), + RFPROC = (1<<4), + RFMEM = (1<<5), + RFNOWAIT = (1<<6), +/* RFCNAMEG = (1<<10), */ +/* RFCENVG = (1<<11), */ + RFCFDG = (1<<12), +/* RFREND = (1<<13), */ +/* RFNOMNT = (1<<14) */ +}; +extern int ffork(int, void(*)(void*), void*); + +/* wait for processes */ +#define wait _p9wait +typedef struct Waitmsg Waitmsg; +struct Waitmsg +{ + int pid; /* of loved one */ + ulong time[3]; /* of loved one & descendants */ + char *msg; +}; +extern int await(char*, int); +extern Waitmsg* wait(void); + +/* synchronization */ +typedef struct Lock Lock; +struct Lock +{ + int val; +}; + +extern int _tas(void*); +extern void lock(Lock*); +extern void unlock(Lock*); +extern int canlock(Lock*); + +typedef struct QLp QLp; +struct QLp +{ + int inuse; + QLp *next; + int state; +}; + +typedef struct QLock QLock; +struct QLock +{ + Lock lock; + int locked; + QLp *head; + QLp *tail; +}; + +extern void qlock(QLock*); +extern void qunlock(QLock*); +extern int canqlock(QLock*); +extern void _qlockinit(ulong (*)(ulong, ulong)); + +typedef struct RWLock RWLock; +struct RWLock +{ + Lock lock; + int readers; + int writer; + QLp *head; + QLp *tail; +}; + +extern void rlock(RWLock*); +extern void runlock(RWLock*); +extern int canrlock(RWLock*); +extern void wlock(RWLock*); +extern void wunlock(RWLock*); +extern int canwlock(RWLock*); + +typedef struct Rendez Rendez; +struct Rendez +{ + QLock *l; + QLp *head; + QLp *tail; +}; + +extern void rsleep(Rendez*); +extern int rwakeup(Rendez*); +extern int rwakeupall(Rendez*); + +extern ulong rendezvous(ulong, ulong); + +/* one of a kind */ +extern void sysfatal(char*, ...); +extern int nrand(int); +extern void setmalloctag(void*, ulong); +extern void setrealloctag(void*, ulong); +extern void *mallocz(ulong, int); +extern long readn(int, void*, long); +extern void exits(char*); +extern void _exits(char*); +extern ulong getcallerpc(void*); + +/* string routines */ +extern char* strecpy(char*, char*, char*); +extern int tokenize(char*, char**, int); +extern int cistrncmp(char*, char*, int); +extern int cistrcmp(char*, char*); +extern char* cistrstr(char*, char*); +extern int getfields(char*, char**, int, int, char*); +extern int gettokens(char *, char **, int, char *); + +/* formatting helpers */ +extern int dec64(uchar*, int, char*, int); +extern int enc64(char*, int, uchar*, int); +extern int dec32(uchar*, int, char*, int); +extern int enc32(char*, int, uchar*, int); +extern int dec16(uchar*, int, char*, int); +extern int enc16(char*, int, uchar*, int); +extern int encodefmt(Fmt*); + +/* error string */ +enum +{ + ERRMAX = 128 +}; +extern void rerrstr(char*, uint); +extern void werrstr(char*, ...); +extern int errstr(char*, uint); + +/* compiler directives on plan 9 */ +#define USED(x) if(x){}else{} +#define SET(x) ((x)=0) + +/* command line */ +extern char *argv0; +#define ARGBEGIN for((argv0||(argv0=*argv)),argv++,argc--;\ + argv[0] && argv[0][0]=='-' && argv[0][1];\ + argc--, argv++) {\ + char *_args, *_argt;\ + Rune _argc;\ + _args = &argv[0][1];\ + if(_args[0]=='-' && _args[1]==0){\ + argc--; argv++; break;\ + }\ + _argc = 0;\ + while(*_args && (_args += chartorune(&_argc, _args)))\ + switch(_argc) +#define ARGEND SET(_argt);USED(_argt);USED(_argc);USED(_args);}USED(argv);USED(argc); +#define ARGF() (_argt=_args, _args="",\ + (*_argt? _argt: argv[1]? (argc--, *++argv): 0)) +#define EARGF(x) (_argt=_args, _args="",\ + (*_argt? _argt: argv[1]? (argc--, *++argv): ((x), abort(), (char*)0))) + +#define ARGC() _argc + +#define OREAD O_RDONLY +#define OWRITE O_WRONLY +#define AEXIST 0 +#define AREAD 4 +#define AWRITE 2 +#define AEXEC 1 + +#if defined(__cplusplus) +} +#endif + +#endif /* _LIB9H_ */ diff --git a/src/lib9/lock.c b/src/lib9/lock.c new file mode 100644 index 00000000..2da73626 --- /dev/null +++ b/src/lib9/lock.c @@ -0,0 +1,54 @@ +#include +#include +#include + +int _ntas; +static int +_xtas(void *v) +{ + int x; + +_ntas++; + x = _tas(v); + if(x == 0 || x == 0xCAFEBABE) + return x; + fprint(2, "%d: tas %p got %ux\n", getpid(), v, x); + abort(); +} + +int +canlock(Lock *l) +{ + return !_xtas(&l->val); +} + +void +unlock(Lock *l) +{ + l->val = 0; +} + +void +lock(Lock *lk) +{ + int i; + + /* once fast */ + if(!_xtas(&lk->val)) + return; + /* a thousand times pretty fast */ + for(i=0; i<1000; i++){ + if(!_xtas(&lk->val)) + return; + sched_yield(); + } + /* now nice and slow */ + for(i=0; i<1000; i++){ + if(!_xtas(&lk->val)) + return; + usleep(100*1000); + } + /* take your time */ + while(_xtas(&lk->val)) + usleep(1000*1000); +} diff --git a/src/lib9/malloctag.c b/src/lib9/malloctag.c new file mode 100644 index 00000000..e5682bc7 --- /dev/null +++ b/src/lib9/malloctag.c @@ -0,0 +1,15 @@ +#include + +void +setmalloctag(void *v, ulong t) +{ + USED(v); + USED(t); +} + +void +setrealloctag(void *v, ulong t) +{ + USED(v); + USED(t); +} diff --git a/src/lib9/mallocz.c b/src/lib9/mallocz.c new file mode 100644 index 00000000..c6313008 --- /dev/null +++ b/src/lib9/mallocz.c @@ -0,0 +1,14 @@ +#include +#include +#include + +void* +mallocz(unsigned long n, int clr) +{ + void *v; + + v = malloc(n); + if(clr && v) + memset(v, 0, n); + return v; +} diff --git a/src/lib9/mkfile b/src/lib9/mkfile new file mode 100644 index 00000000..703f6b06 --- /dev/null +++ b/src/lib9/mkfile @@ -0,0 +1,2 @@ +<../libutf/mkfile + diff --git a/src/lib9/nrand.c b/src/lib9/nrand.c new file mode 100644 index 00000000..cf9c17c3 --- /dev/null +++ b/src/lib9/nrand.c @@ -0,0 +1,17 @@ +#include + +#define MASK 0x7fffffffL + +int +nrand(int n) +{ + long slop, v; + + if(n < 0) + return n; + slop = MASK % n; + do + v = lrand(); + while(v <= slop); + return v % n; +} diff --git a/src/lib9/qlock.c b/src/lib9/qlock.c new file mode 100644 index 00000000..55a18466 --- /dev/null +++ b/src/lib9/qlock.c @@ -0,0 +1,360 @@ +#include + +static struct { + QLp *p; + QLp x[1024]; +} ql = { + ql.x +}; + +enum +{ + Queuing, + QueuingR, + QueuingW, + Sleeping, +}; + +static ulong (*_rendezvousp)(ulong, ulong) = rendezvous; + +/* this gets called by the thread library ONLY to get us to use its rendezvous */ +void +_qlockinit(ulong (*r)(ulong, ulong)) +{ + _rendezvousp = r; +} + +/* find a free shared memory location to queue ourselves in */ +static QLp* +getqlp(void) +{ + QLp *p, *op; + + op = ql.p; + for(p = op+1; ; p++){ + if(p == &ql.x[nelem(ql.x)]) + p = ql.x; + if(p == op) + abort(); + if(_tas(&(p->inuse)) == 0){ + ql.p = p; + p->next = nil; + break; + } + } + return p; +} + +void +qlock(QLock *q) +{ + QLp *p, *mp; + + lock(&q->lock); + if(!q->locked){ + q->locked = 1; + unlock(&q->lock); + return; + } + + + /* chain into waiting list */ + mp = getqlp(); + p = q->tail; + if(p == nil) + q->head = mp; + else + p->next = mp; + q->tail = mp; + mp->state = Queuing; + unlock(&q->lock); + + /* wait */ + while((*_rendezvousp)((ulong)mp, 1) == ~0) + ; + mp->inuse = 0; +} + +void +qunlock(QLock *q) +{ + QLp *p; + + lock(&q->lock); + p = q->head; + if(p != nil){ + /* wakeup head waiting process */ + q->head = p->next; + if(q->head == nil) + q->tail = nil; + unlock(&q->lock); + while((*_rendezvousp)((ulong)p, 0x12345) == ~0) + ; + return; + } + q->locked = 0; + unlock(&q->lock); +} + +int +canqlock(QLock *q) +{ + if(!canlock(&q->lock)) + return 0; + if(!q->locked){ + q->locked = 1; + unlock(&q->lock); + return 1; + } + unlock(&q->lock); + return 0; +} + +void +rlock(RWLock *q) +{ + QLp *p, *mp; + + lock(&q->lock); + if(q->writer == 0 && q->head == nil){ + /* no writer, go for it */ + q->readers++; + unlock(&q->lock); + return; + } + + mp = getqlp(); + p = q->tail; + if(p == 0) + q->head = mp; + else + p->next = mp; + q->tail = mp; + mp->next = nil; + mp->state = QueuingR; + unlock(&q->lock); + + /* wait in kernel */ + while((*_rendezvousp)((ulong)mp, 1) == ~0) + ; + mp->inuse = 0; +} + +int +canrlock(RWLock *q) +{ + lock(&q->lock); + if (q->writer == 0 && q->head == nil) { + /* no writer; go for it */ + q->readers++; + unlock(&q->lock); + return 1; + } + unlock(&q->lock); + return 0; +} + +void +runlock(RWLock *q) +{ + QLp *p; + + lock(&q->lock); + if(q->readers <= 0) + abort(); + p = q->head; + if(--(q->readers) > 0 || p == nil){ + unlock(&q->lock); + return; + } + + /* start waiting writer */ + if(p->state != QueuingW) + abort(); + q->head = p->next; + if(q->head == 0) + q->tail = 0; + q->writer = 1; + unlock(&q->lock); + + /* wakeup waiter */ + while((*_rendezvousp)((ulong)p, 0) == ~0) + ; +} + +void +wlock(RWLock *q) +{ + QLp *p, *mp; + + lock(&q->lock); + if(q->readers == 0 && q->writer == 0){ + /* noone waiting, go for it */ + q->writer = 1; + unlock(&q->lock); + return; + } + + /* wait */ + p = q->tail; + mp = getqlp(); + if(p == nil) + q->head = mp; + else + p->next = mp; + q->tail = mp; + mp->next = nil; + mp->state = QueuingW; + unlock(&q->lock); + + /* wait in kernel */ + while((*_rendezvousp)((ulong)mp, 1) == ~0) + ; + mp->inuse = 0; +} + +int +canwlock(RWLock *q) +{ + lock(&q->lock); + if (q->readers == 0 && q->writer == 0) { + /* no one waiting; go for it */ + q->writer = 1; + unlock(&q->lock); + return 1; + } + unlock(&q->lock); + return 0; +} + +void +wunlock(RWLock *q) +{ + QLp *p; + + lock(&q->lock); + if(q->writer == 0) + abort(); + p = q->head; + if(p == nil){ + q->writer = 0; + unlock(&q->lock); + return; + } + if(p->state == QueuingW){ + /* start waiting writer */ + q->head = p->next; + if(q->head == nil) + q->tail = nil; + unlock(&q->lock); + while((*_rendezvousp)((ulong)p, 0) == ~0) + ; + return; + } + + if(p->state != QueuingR) + abort(); + + /* wake waiting readers */ + while(q->head != nil && q->head->state == QueuingR){ + p = q->head; + q->head = p->next; + q->readers++; + while((*_rendezvousp)((ulong)p, 0) == ~0) + ; + } + if(q->head == nil) + q->tail = nil; + q->writer = 0; + unlock(&q->lock); +} + +void +rsleep(Rendez *r) +{ + QLp *t, *me; + + if(!r->l) + abort(); + lock(&r->l->lock); + /* we should hold the qlock */ + if(!r->l->locked) + abort(); + + /* add ourselves to the wait list */ + me = getqlp(); + me->state = Sleeping; + if(r->head == nil) + r->head = me; + else + r->tail->next = me; + me->next = nil; + r->tail = me; + + /* pass the qlock to the next guy */ + t = r->l->head; + if(t){ + r->l->head = t->next; + if(r->l->head == nil) + r->l->tail = nil; + unlock(&r->l->lock); + while((*_rendezvousp)((ulong)t, 0x12345) == ~0) + ; + }else{ + r->l->locked = 0; + unlock(&r->l->lock); + } + + /* wait for a wakeup */ + while((*_rendezvousp)((ulong)me, 0x23456) == ~0) + ; + me->inuse = 0; + if(!r->l->locked) + abort(); +} + +int +rwakeup(Rendez *r) +{ + QLp *t; + + /* + * take off wait and put on front of queue + * put on front so guys that have been waiting will not get starved + */ + + if(!r->l) + abort(); + lock(&r->l->lock); + if(!r->l->locked) + abort(); + + t = r->head; + if(t == nil){ + unlock(&r->l->lock); + return 0; + } + + r->head = t->next; + if(r->head == nil) + r->tail = nil; + + t->next = r->l->head; + r->l->head = t; + if(r->l->tail == nil) + r->l->tail = t; + + t->state = Queuing; + unlock(&r->l->lock); + return 1; +} + +int +rwakeupall(Rendez *r) +{ + int i; + + for(i=0; rwakeup(r); i++) + ; + return i; +} diff --git a/src/lib9/rand.c b/src/lib9/rand.c new file mode 100644 index 00000000..34f77eca --- /dev/null +++ b/src/lib9/rand.c @@ -0,0 +1,89 @@ +#include + +/* + * algorithm by + * D. P. Mitchell & J. A. Reeds + */ + +#define LEN 607 +#define TAP 273 +#define MASK 0x7fffffffL +#define A 48271 +#define M 2147483647 +#define Q 44488 +#define R 3399 +#define NORM (1.0/(1.0+MASK)) + +static ulong rng_vec[LEN]; +static ulong* rng_tap = rng_vec; +static ulong* rng_feed = 0; +static Lock lk; + +static void +isrand(long seed) +{ + long lo, hi, x; + int i; + + rng_tap = rng_vec; + rng_feed = rng_vec+LEN-TAP; + seed = seed%M; + if(seed < 0) + seed += M; + if(seed == 0) + seed = 89482311; + x = seed; + /* + * Initialize by x[n+1] = 48271 * x[n] mod (2**31 - 1) + */ + for(i = -20; i < LEN; i++) { + hi = x / Q; + lo = x % Q; + x = A*lo - R*hi; + if(x < 0) + x += M; + if(i >= 0) + rng_vec[i] = x; + } +} + +void +srand(long seed) +{ + lock(&lk); + isrand(seed); + unlock(&lk); +} + +long +lrand(void) +{ + ulong x; + + lock(&lk); + + rng_tap--; + if(rng_tap < rng_vec) { + if(rng_feed == 0) { + isrand(1); + rng_tap--; + } + rng_tap += LEN; + } + rng_feed--; + if(rng_feed < rng_vec) + rng_feed += LEN; + x = (*rng_feed + *rng_tap) & MASK; + *rng_feed = x; + + unlock(&lk); + + return x; +} + +int +rand(void) +{ + return lrand() & 0x7fff; +} + diff --git a/src/lib9/readn.c b/src/lib9/readn.c new file mode 100644 index 00000000..e7b9d138 --- /dev/null +++ b/src/lib9/readn.c @@ -0,0 +1,21 @@ +#include + +long +readn(int f, void *av, long n) +{ + char *a; + long m, t; + + a = av; + t = 0; + while(t < n){ + m = read(f, a+t, n-t); + if(m <= 0){ + if(t == 0) + return m; + break; + } + t += m; + } + return t; +} diff --git a/src/lib9/rendez.c b/src/lib9/rendez.c new file mode 100644 index 00000000..320bd11a --- /dev/null +++ b/src/lib9/rendez.c @@ -0,0 +1,180 @@ +/* + NAME + rendezvous - user level process synchronization + + SYNOPSIS + ulong rendezvous(ulong tag, ulong value) + + DESCRIPTION + The rendezvous system call allows two processes to synchro- + nize and exchange a value. In conjunction with the shared + memory system calls (see segattach(2) and fork(2)), it + enables parallel programs to control their scheduling. + + Two processes wishing to synchronize call rendezvous with a + common tag, typically an address in memory they share. One + process will arrive at the rendezvous first; it suspends + execution until a second arrives. When a second process + meets the rendezvous the value arguments are exchanged + between the processes and returned as the result of the + respective rendezvous system calls. Both processes are + awakened when the rendezvous succeeds. + + The set of tag values which two processes may use to + rendezvous-their tag space-is inherited when a process + forks, unless RFREND is set in the argument to rfork; see + fork(2). + + If a rendezvous is interrupted the return value is ~0, so + that value should not be used in normal communication. + + * This simulates rendezvous with shared memory, pause, and SIGUSR1. + */ + +#include +#include + +enum +{ + VOUSHASH = 257, +}; + +typedef struct Vous Vous; +struct Vous +{ + Vous *link; + Lock lk; + int pid; + ulong val; + ulong tag; +}; + +static void +ign(int x) +{ + USED(x); +} + +void /*__attribute__((constructor))*/ +ignusr1(void) +{ + signal(SIGUSR1, ign); +} + +static Vous vouspool[2048]; +static int nvousused; +static Vous *vousfree; +static Vous *voushash[VOUSHASH]; +static Lock vouslock; + +static Vous* +getvous(void) +{ + Vous *v; + + if(vousfree){ + v = vousfree; + vousfree = v->link; + }else if(nvousused < nelem(vouspool)) + v = &vouspool[nvousused++]; + else + abort(); + return v; +} + +static void +putvous(Vous *v) +{ + lock(&vouslock); + v->link = vousfree; + vousfree = v; + unlock(&vouslock); +} + +static Vous* +findvous(ulong tag, ulong val, int pid) +{ + int h; + Vous *v, **l; + + lock(&vouslock); + h = tag%VOUSHASH; + for(l=&voushash[h], v=*l; v; l=&(*l)->link, v=*l){ + if(v->tag == tag){ + *l = v->link; + unlock(&vouslock); + return v; + } + } + v = getvous(); + v->pid = pid; + v->link = voushash[h]; + v->val = val; + v->tag = tag; + lock(&v->lk); + voushash[h] = v; + unlock(&vouslock); + return v; +} + +#define DBG 0 +ulong +rendezvous(ulong tag, ulong val) +{ + int me, vpid; + ulong rval; + Vous *v; + sigset_t mask; + + me = getpid(); + v = findvous(tag, val, me); + if(v->pid == me){ + if(DBG)fprint(2, "pid is %d tag %lux, sleeping\n", me, tag); + /* + * No rendezvous partner was found; the next guy + * through will find v and wake us, so we must go + * to sleep. + * + * To go to sleep: + * 1. disable USR1 signals. + * 2. unlock v->lk (tells waker okay to signal us). + * 3. atomically suspend and enable USR1 signals. + * + * The call to ignusr1() could be done once at + * process creation instead of every time through rendezvous. + */ + v->val = val; + ignusr1(); + sigprocmask(SIG_SETMASK, NULL, &mask); + sigaddset(&mask, SIGUSR1); + sigprocmask(SIG_SETMASK, &mask, NULL); + sigdelset(&mask, SIGUSR1); + unlock(&v->lk); + sigsuspend(&mask); + rval = v->val; + if(DBG)fprint(2, "pid is %d, awake\n", me); + putvous(v); + }else{ + /* + * Found someone to meet. Wake him: + * + * A. lock v->lk (waits for him to get to his step 2) + * B. send a USR1 + * + * He won't get the USR1 until he suspends, which + * means it must wake him up (it can't get delivered + * before he sleeps). + */ + vpid = v->pid; + lock(&v->lk); + rval = v->val; + v->val = val; + unlock(&v->lk); + if(kill(vpid, SIGUSR1) < 0){ + if(DBG)fprint(2, "pid is %d, kill %d failed: %r\n", me, vpid); + abort(); + } + } + return rval; +} + diff --git a/src/lib9/strecpy.c b/src/lib9/strecpy.c new file mode 100644 index 00000000..7d2f2277 --- /dev/null +++ b/src/lib9/strecpy.c @@ -0,0 +1,16 @@ +#include + +char* +strecpy(char *to, char *e, char *from) +{ + if(to >= e) + return to; + to = memccpy(to, from, '\0', e - to); + if(to == nil){ + to = e - 1; + *to = '\0'; + }else{ + to--; + } + return to; +} diff --git a/src/lib9/sysfatal.c b/src/lib9/sysfatal.c new file mode 100644 index 00000000..f9ab6985 --- /dev/null +++ b/src/lib9/sysfatal.c @@ -0,0 +1,20 @@ +#include + +void (*_sysfatal)(char*, ...); + +void +sysfatal(char *fmt, ...) +{ + char buf[256]; + va_list arg; + + va_start(arg, fmt); + if(_sysfatal) + (*_sysfatal)(fmt, arg); + vseprint(buf, buf+sizeof buf, fmt, arg); + va_end(arg); + + fprint(2, "%s; %s\n", argv0 ? argv0 : "", buf); + exits("fatal"); +} + diff --git a/src/lib9/tas-386.s b/src/lib9/tas-386.s new file mode 100644 index 00000000..7a62d2d3 --- /dev/null +++ b/src/lib9/tas-386.s @@ -0,0 +1,6 @@ +.globl _tas +_tas: + movl $0xCAFEBABE, %eax + movl 4(%esp), %ecx + xchgl %eax, 0(%ecx) + ret diff --git a/src/lib9/test.c b/src/lib9/test.c new file mode 100644 index 00000000..3a358c6c --- /dev/null +++ b/src/lib9/test.c @@ -0,0 +1,8 @@ +#include + +int +main(int argc, char **argv) +{ + werrstr("hello world"); + print("%r\n"); +} diff --git a/src/lib9/testfork.c b/src/lib9/testfork.c new file mode 100644 index 00000000..a5e63718 --- /dev/null +++ b/src/lib9/testfork.c @@ -0,0 +1,21 @@ +#include + +void +sayhi(void *v) +{ + USED(v); + + print("hello from subproc\n"); + print("rendez got %lu from main\n", rendezvous(0x1234, 1234)); + exits(0); +} + +int +main(int argc, char **argv) +{ + print("hello from main\n"); + ffork(RFMEM|RFPROC, sayhi, nil); + + print("rendez got %lu from subproc\n", rendezvous(0x1234, 0)); + exits(0); +} diff --git a/src/lib9/tokenize.c b/src/lib9/tokenize.c new file mode 100644 index 00000000..6fa9fc73 --- /dev/null +++ b/src/lib9/tokenize.c @@ -0,0 +1,106 @@ +#include + +static char qsep[] = " \t\r\n"; + +static char* +qtoken(char *s, char *sep) +{ + int quoting; + char *t; + + quoting = 0; + t = s; /* s is output string, t is input string */ + while(*t!='\0' && (quoting || utfrune(sep, *t)==nil)){ + if(*t != '\''){ + *s++ = *t++; + continue; + } + /* *t is a quote */ + if(!quoting){ + quoting = 1; + t++; + continue; + } + /* quoting and we're on a quote */ + if(t[1] != '\''){ + /* end of quoted section; absorb closing quote */ + t++; + quoting = 0; + continue; + } + /* doubled quote; fold one quote into two */ + t++; + *s++ = *t++; + } + if(*s != '\0'){ + *s = '\0'; + if(t == s) + t++; + } + return t; +} + +static char* +etoken(char *t, char *sep) +{ + int quoting; + + /* move to end of next token */ + quoting = 0; + while(*t!='\0' && (quoting || utfrune(sep, *t)==nil)){ + if(*t != '\''){ + t++; + continue; + } + /* *t is a quote */ + if(!quoting){ + quoting = 1; + t++; + continue; + } + /* quoting and we're on a quote */ + if(t[1] != '\''){ + /* end of quoted section; absorb closing quote */ + t++; + quoting = 0; + continue; + } + /* doubled quote; fold one quote into two */ + t += 2; + } + return t; +} + +int +gettokens(char *s, char **args, int maxargs, char *sep) +{ + int nargs; + + for(nargs=0; nargs +static char t16e[] = "0123456789ABCDEF"; + +int +dec16(uchar *out, int lim, char *in, int n) +{ + int c, w = 0, i = 0; + uchar *start = out; + uchar *eout = out + lim; + + while(n-- > 0){ + c = *in++; + if('0' <= c && c <= '9') + c = c - '0'; + else if('a' <= c && c <= 'z') + c = c - 'a' + 10; + else if('A' <= c && c <= 'Z') + c = c - 'A' + 10; + else + continue; + w = (w<<4) + c; + i++; + if(i == 2){ + if(out + 1 > eout) + goto exhausted; + *out++ = w; + w = 0; + i = 0; + } + } +exhausted: + return out - start; +} + +int +enc16(char *out, int lim, uchar *in, int n) +{ + uint c; + char *eout = out + lim; + char *start = out; + + while(n-- > 0){ + c = *in++; + if(out + 2 >= eout) + goto exhausted; + *out++ = t16e[c>>4]; + *out++ = t16e[c&0xf]; + } +exhausted: + *out = 0; + return out - start; +} diff --git a/src/lib9/u32.c b/src/lib9/u32.c new file mode 100644 index 00000000..1eb0c6e0 --- /dev/null +++ b/src/lib9/u32.c @@ -0,0 +1,109 @@ +#include + +int +dec32(uchar *dest, int ndest, char *src, int nsrc) +{ + char *s, *tab; + uchar *start; + int i, u[8]; + + if(ndest+1 < (5*nsrc+7)/8) + return -1; + start = dest; + tab = "23456789abcdefghijkmnpqrstuvwxyz"; + while(nsrc>=8){ + for(i=0; i<8; i++){ + s = strchr(tab,(int)src[i]); + u[i] = s ? s-tab : 0; + } + *dest++ = (u[0]<<3) | (0x7 & (u[1]>>2)); + *dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4)); + *dest++ = ((0xf & u[3])<<4) | (0xf & (u[4]>>1)); + *dest++ = ((0x1 & u[4])<<7) | (u[5]<<2) | (0x3 & (u[6]>>3)); + *dest++ = ((0x7 & u[6])<<5) | u[7]; + src += 8; + nsrc -= 8; + } + if(nsrc > 0){ + if(nsrc == 1 || nsrc == 3 || nsrc == 6) + return -1; + for(i=0; i>2)); + if(nsrc == 2) + goto out; + *dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4)); + if(nsrc == 4) + goto out; + *dest++ = ((0xf & u[3])<<4) | (0xf & (u[4]>>1)); + if(nsrc == 5) + goto out; + *dest++ = ((0x1 & u[4])<<7) | (u[5]<<2) | (0x3 & (u[6]>>3)); + } +out: + return dest-start; +} + +int +enc32(char *dest, int ndest, uchar *src, int nsrc) +{ + char *tab, *start; + int j; + + if(ndest <= (8*nsrc+4)/5 ) + return -1; + start = dest; + tab = "23456789abcdefghijkmnpqrstuvwxyz"; + while(nsrc>=5){ + j = (0x1f & (src[0]>>3)); + *dest++ = tab[j]; + j = (0x1c & (src[0]<<2)) | (0x03 & (src[1]>>6)); + *dest++ = tab[j]; + j = (0x1f & (src[1]>>1)); + *dest++ = tab[j]; + j = (0x10 & (src[1]<<4)) | (0x0f & (src[2]>>4)); + *dest++ = tab[j]; + j = (0x1e & (src[2]<<1)) | (0x01 & (src[3]>>7)); + *dest++ = tab[j]; + j = (0x1f & (src[3]>>2)); + *dest++ = tab[j]; + j = (0x18 & (src[3]<<3)) | (0x07 & (src[4]>>5)); + *dest++ = tab[j]; + j = (0x1f & (src[4])); + *dest++ = tab[j]; + src += 5; + nsrc -= 5; + } + if(nsrc){ + j = (0x1f & (src[0]>>3)); + *dest++ = tab[j]; + j = (0x1c & (src[0]<<2)); + if(nsrc == 1) + goto out; + j |= (0x03 & (src[1]>>6)); + *dest++ = tab[j]; + j = (0x1f & (src[1]>>1)); + if(nsrc == 2) + goto out; + *dest++ = tab[j]; + j = (0x10 & (src[1]<<4)); + if(nsrc == 3) + goto out; + j |= (0x0f & (src[2]>>4)); + *dest++ = tab[j]; + j = (0x1e & (src[2]<<1)); + if(nsrc == 4) + goto out; + j |= (0x01 & (src[3]>>7)); + *dest++ = tab[j]; + j = (0x1f & (src[3]>>2)); + *dest++ = tab[j]; + j = (0x18 & (src[3]<<3)); +out: + *dest++ = tab[j]; + } + *dest = 0; + return dest-start; +} diff --git a/src/lib9/u64.c b/src/lib9/u64.c new file mode 100644 index 00000000..a17bdf1d --- /dev/null +++ b/src/lib9/u64.c @@ -0,0 +1,126 @@ +#include + +enum { + INVAL= 255 +}; + +static uchar t64d[256] = { + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, 62,INVAL,INVAL,INVAL, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL, 0, 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,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL, 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,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL +}; +static char t64e[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +int +dec64(uchar *out, int lim, char *in, int n) +{ + ulong b24; + uchar *start = out; + uchar *e = out + lim; + int i, c; + + b24 = 0; + i = 0; + while(n-- > 0){ + + c = t64d[*(uchar*)in++]; + if(c == INVAL) + continue; + switch(i){ + case 0: + b24 = c<<18; + break; + case 1: + b24 |= c<<12; + break; + case 2: + b24 |= c<<6; + break; + case 3: + if(out + 3 > e) + goto exhausted; + + b24 |= c; + *out++ = b24>>16; + *out++ = b24>>8; + *out++ = b24; + i = -1; + break; + } + i++; + } + switch(i){ + case 2: + if(out + 1 > e) + goto exhausted; + *out++ = b24>>16; + break; + case 3: + if(out + 2 > e) + goto exhausted; + *out++ = b24>>16; + *out++ = b24>>8; + break; + } +exhausted: + return out - start; +} + +int +enc64(char *out, int lim, uchar *in, int n) +{ + int i; + ulong b24; + char *start = out; + char *e = out + lim; + + for(i = n/3; i > 0; i--){ + b24 = (*in++)<<16; + b24 |= (*in++)<<8; + b24 |= *in++; + if(out + 4 >= e) + goto exhausted; + *out++ = t64e[(b24>>18)]; + *out++ = t64e[(b24>>12)&0x3f]; + *out++ = t64e[(b24>>6)&0x3f]; + *out++ = t64e[(b24)&0x3f]; + } + + switch(n%3){ + case 2: + b24 = (*in++)<<16; + b24 |= (*in)<<8; + if(out + 4 >= e) + goto exhausted; + *out++ = t64e[(b24>>18)]; + *out++ = t64e[(b24>>12)&0x3f]; + *out++ = t64e[(b24>>6)&0x3f]; + *out++ = '='; + break; + case 1: + b24 = (*in)<<16; + if(out + 4 >= e) + goto exhausted; + *out++ = t64e[(b24>>18)]; + *out++ = t64e[(b24>>12)&0x3f]; + *out++ = '='; + *out++ = '='; + break; + } +exhausted: + *out = 0; + return out - start; +} diff --git a/src/lib9/wait.c b/src/lib9/wait.c new file mode 100644 index 00000000..14af7156 --- /dev/null +++ b/src/lib9/wait.c @@ -0,0 +1,30 @@ +#include + +Waitmsg* +wait(void) +{ + int n, l; + char buf[512], *fld[5]; + Waitmsg *w; + + n = await(buf, sizeof buf-1); + if(n < 0) + return nil; + buf[n] = '\0'; + if(tokenize(buf, fld, nelem(fld)) != nelem(fld)){ + werrstr("couldn't parse wait message"); + return nil; + } + l = strlen(fld[4])+1; + w = malloc(sizeof(Waitmsg)+l); + if(w == nil) + return nil; + w->pid = atoi(fld[0]); + w->time[0] = atoi(fld[1]); + w->time[1] = atoi(fld[2]); + w->time[2] = atoi(fld[3]); + w->msg = (char*)&w[1]; + memmove(w->msg, fld[4], l); + return w; +} + diff --git a/src/lib9/werrstr.c b/src/lib9/werrstr.c new file mode 100644 index 00000000..7fa1f2ea --- /dev/null +++ b/src/lib9/werrstr.c @@ -0,0 +1,13 @@ +#include + +void +werrstr(char *fmt, ...) +{ + va_list arg; + char buf[ERRMAX]; + + va_start(arg, fmt); + vseprint(buf, buf+ERRMAX, fmt, arg); + va_end(arg); + errstr(buf, ERRMAX); +} -- cgit v1.2.3