3 #define INCL_DOSFILEMGR
8 #include <sys/uflags.h>
11 * Various Unix compatibility functions for OS/2
25 typedef void (*emx_startroutine)(void *);
26 typedef void* (*pthreads_startroutine)(void *);
35 const char *pthreads_states[] = {
46 enum pthreads_state state;
49 thread_join_t *thread_join_data;
50 int thread_join_count;
51 perl_mutex start_thread_mutex;
54 pthread_join(perl_os_thread tid, void **status)
56 MUTEX_LOCK(&start_thread_mutex);
57 switch (thread_join_data[tid].state) {
58 case pthreads_st_exited:
59 thread_join_data[tid].state = pthreads_st_none; /* Ready to reuse */
60 MUTEX_UNLOCK(&start_thread_mutex);
61 *status = thread_join_data[tid].status;
63 case pthreads_st_waited:
64 MUTEX_UNLOCK(&start_thread_mutex);
65 croak("join with a thread with a waiter");
68 thread_join_data[tid].state = pthreads_st_waited;
69 COND_INIT(&thread_join_data[tid].cond);
70 MUTEX_UNLOCK(&start_thread_mutex);
71 COND_WAIT(&thread_join_data[tid].cond, NULL);
72 COND_DESTROY(&thread_join_data[tid].cond);
73 thread_join_data[tid].state = pthreads_st_none; /* Ready to reuse */
74 *status = thread_join_data[tid].status;
77 MUTEX_UNLOCK(&start_thread_mutex);
78 croak("join: unknown thread state: '%s'",
79 pthreads_states[thread_join_data[tid].state]);
86 pthread_startit(void *arg)
88 /* Thread is already started, we need to transfer control only */
89 pthreads_startroutine start_routine = *((pthreads_startroutine*)arg);
90 int tid = pthread_self();
93 arg = ((void**)arg)[1];
94 if (tid >= thread_join_count) {
95 int oc = thread_join_count;
97 thread_join_count = tid + 5 + tid/5;
98 if (thread_join_data) {
99 Renew(thread_join_data, thread_join_count, thread_join_t);
100 Zero(thread_join_data + oc, thread_join_count - oc, thread_join_t);
102 Newz(1323, thread_join_data, thread_join_count, thread_join_t);
105 if (thread_join_data[tid].state != pthreads_st_none)
106 croak("attempt to reuse thread id %i", tid);
107 thread_join_data[tid].state = pthreads_st_run;
108 /* Now that we copied/updated the guys, we may release the caller... */
109 MUTEX_UNLOCK(&start_thread_mutex);
110 thread_join_data[tid].status = (*start_routine)(arg);
111 switch (thread_join_data[tid].state) {
112 case pthreads_st_waited:
113 COND_SIGNAL(&thread_join_data[tid].cond);
116 thread_join_data[tid].state = pthreads_st_exited;
122 pthread_create(perl_os_thread *tid, const pthread_attr_t *attr,
123 void *(*start_routine)(void*), void *arg)
127 args[0] = (void*)start_routine;
130 MUTEX_LOCK(&start_thread_mutex);
131 *tid = _beginthread(pthread_startit, /*stack*/ NULL,
132 /*stacksize*/ 10*1024*1024, (void*)args);
133 MUTEX_LOCK(&start_thread_mutex);
134 MUTEX_UNLOCK(&start_thread_mutex);
135 return *tid ? 0 : EINVAL;
139 pthread_detach(perl_os_thread tid)
141 MUTEX_LOCK(&start_thread_mutex);
142 switch (thread_join_data[tid].state) {
143 case pthreads_st_waited:
144 MUTEX_UNLOCK(&start_thread_mutex);
145 croak("detach on a thread with a waiter");
147 case pthreads_st_run:
148 thread_join_data[tid].state = pthreads_st_detached;
149 MUTEX_UNLOCK(&start_thread_mutex);
152 MUTEX_UNLOCK(&start_thread_mutex);
153 croak("detach: unknown thread state: '%s'",
154 pthreads_states[thread_join_data[tid].state]);
160 /* This is a very bastardized version: */
162 os2_cond_wait(perl_cond *c, perl_mutex *m)
165 if ((rc = DosResetEventSem(*c,&PL_na)) && (rc != ERROR_ALREADY_RESET))
166 croak("panic: COND_WAIT-reset: rc=%i", rc);
167 if (m) MUTEX_UNLOCK(m);
168 if (CheckOSError(DosWaitEventSem(*c,SEM_INDEFINITE_WAIT))
169 && (rc != ERROR_INTERRUPT))
170 croak("panic: COND_WAIT: rc=%i", rc);
171 if (rc == ERROR_INTERRUPT)
173 if (m) MUTEX_LOCK(m);
177 /*****************************************************************************/
178 /* 2.1 would not resolve symbols on demand, and has no ExtLIBPATH. */
179 static PFN ExtFCN[2]; /* Labeled by ord below. */
180 static USHORT loadOrd[2] = { 874, 873 }; /* Query=874, Set=873. */
181 #define ORD_QUERY_ELP 0
182 #define ORD_SET_ELP 1
183 struct PMWIN_entries_t PMWIN_entries;
186 loadByOrd(char *modname, ULONG ord)
188 if (ExtFCN[ord] == NULL) {
189 static HMODULE hdosc = 0;
194 if ((!hdosc && CheckOSError(DosLoadModule(buf, sizeof buf,
196 || CheckOSError(DosQueryProcAddr(hdosc, loadOrd[ord], NULL, &fcn)))
197 croak("This version of OS/2 does not support %s.%i",
198 modname, loadOrd[ord]);
201 if ((long)ExtFCN[ord] == -1)
202 croak("panic queryaddr");
206 init_PMWIN_entries(void)
208 static HMODULE hpmwin = 0;
209 static const int ords[] = {
210 763, /* Initialize */
211 716, /* CreateMsgQueue */
212 726, /* DestroyMsgQueue */
215 912, /* DispatchMsg */
224 if (CheckOSError(DosLoadModule(buf, sizeof buf, "pmwin", &hpmwin)))
225 croak("This version of OS/2 does not support pmwin: error in %s", buf);
227 if (CheckOSError(DosQueryProcAddr(hpmwin, ords[i], NULL,
228 ((PFN*)&PMWIN_entries)+i)))
229 croak("This version of OS/2 does not support pmwin.%d", ords[i]);
236 static signed char priors[] = {0, 1, 3, 2}; /* Last two interchanged,
238 #define QSS_INI_BUFFER 1024
241 get_sysinfo(ULONG pid, ULONG flags)
244 ULONG rc, buf_len = QSS_INI_BUFFER;
246 New(1322, pbuffer, buf_len, char);
247 /* QSS_PROCESS | QSS_MODULE | QSS_SEMAPHORES | QSS_SHARED */
248 rc = QuerySysState(flags, pid, pbuffer, buf_len);
249 while (rc == ERROR_BUFFER_OVERFLOW) {
250 Renew(pbuffer, buf_len *= 2, char);
251 rc = QuerySysState(flags, pid, pbuffer, buf_len);
258 return (PQTOPLEVEL)pbuffer;
261 #define PRIO_ERR 0x1111
269 psi = get_sysinfo(pid, QSS_PROCESS);
273 if (pid != psi->procdata->pid) {
275 croak("panic: wrong pid in sysinfo");
277 prio = psi->procdata->threads->priority;
283 setpriority(int which, int pid, int val)
288 prio = sys_prio(pid);
290 if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */
291 if (priors[(32 - val) >> 5] + 1 == (prio >> 8)) {
292 /* Do not change class. */
293 return CheckOSError(DosSetPriority((pid < 0)
294 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
296 (32 - val) % 32 - (prio & 0xFF),
299 } else /* if ((32 - val) % 32 == (prio & 0xFF)) */ {
300 /* Documentation claims one can change both class and basevalue,
301 * but I find it wrong. */
302 /* Change class, but since delta == 0 denotes absolute 0, correct. */
303 if (CheckOSError(DosSetPriority((pid < 0)
304 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
305 priors[(32 - val) >> 5] + 1,
309 if ( ((32 - val) % 32) == 0 ) return 0;
310 return CheckOSError(DosSetPriority((pid < 0)
311 ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
317 /* else return CheckOSError(DosSetPriority((pid < 0) */
318 /* ? PRTYS_PROCESSTREE : PRTYS_PROCESS, */
319 /* priors[(32 - val) >> 5] + 1, */
320 /* (32 - val) % 32 - (prio & 0xFF), */
326 getpriority(int which /* ignored */, int pid)
332 if (!(_emx_env & 0x200)) return 0; /* Nop if not OS/2. */
333 /* DosGetInfoBlocks has old priority! */
334 /* if (CheckOSError(DosGetInfoBlocks(&tib, &pib))) return -1; */
335 /* if (pid != pib->pib_ulpid) { */
337 if (ret == PRIO_ERR) {
341 /* ret = tib->tib_ptib2->tib2_ulpri; */
342 return (1 - priors[((ret >> 8) - 1)])*32 - (ret & 0xFF);
345 /*****************************************************************************/
348 /* There is no big sense to make it thread-specific, since signals
349 are delivered to thread 1 only. XXXX Maybe make it into an array? */
350 static int spawn_pid;
351 static int spawn_killed;
354 spawn_sighandler(int sig)
356 /* Some programs do not arrange for the keyboard signals to be
357 delivered to them. We need to deliver the signal manually. */
358 /* We may get a signal only if
359 a) kid does not receive keyboard signal: deliver it;
360 b) kid already died, and we get a signal. We may only hope
361 that the pid number was not reused.
365 sig = SIGKILL; /* Try harder. */
366 kill(spawn_pid, sig);
371 result(int flag, int pid)
374 Signal_t (*ihand)(); /* place to save signal during system() */
375 Signal_t (*qhand)(); /* place to save signal during system() */
381 if (pid < 0 || flag != 0)
387 ihand = rsignal(SIGINT, &spawn_sighandler);
388 qhand = rsignal(SIGQUIT, &spawn_sighandler);
390 r = wait4pid(pid, &status, 0);
391 } while (r == -1 && errno == EINTR);
392 rsignal(SIGINT, ihand);
393 rsignal(SIGQUIT, qhand);
395 PL_statusvalue = (U16)status;
398 return status & 0xFFFF;
400 ihand = rsignal(SIGINT, SIG_IGN);
401 r = DosWaitChild(DCWA_PROCESS, DCWW_WAIT, &res, &rpid, pid);
402 rsignal(SIGINT, ihand);
403 PL_statusvalue = res.codeResult << 8 | res.codeTerminate;
406 return PL_statusvalue;
410 #define EXECF_SPAWN 0
412 #define EXECF_TRUEEXEC 2
413 #define EXECF_SPAWN_NOWAIT 3
415 /* const char* const ptypes[] = { "FS", "DOS", "VIO", "PM", "DETACH" }; */
424 if (!(_emx_env & 0x200)) return 1; /* not OS/2. */
425 if (CheckOSError(DosGetInfoBlocks(&tib, &pib)))
428 return (pib->pib_ultype);
432 file_type(char *path)
437 if (!(_emx_env & 0x200))
438 croak("file_type not implemented on DOS"); /* not OS/2. */
439 if (CheckOSError(DosQueryAppType(path, &apptype))) {
441 case ERROR_FILE_NOT_FOUND:
442 case ERROR_PATH_NOT_FOUND:
444 case ERROR_ACCESS_DENIED: /* Directory with this name found? */
446 default: /* Found, but not an
447 executable, or some other
455 static ULONG os2_mytype;
457 /* Spawn/exec a program, revert to shell if needed. */
458 /* global PL_Argv[] contains arguments. */
461 do_spawn_ve(really, flag, execf, inicmd)
471 char buf[256], *s = 0, scrbuf[280];
473 static char * fargs[4]
474 = { "/bin/sh", "-c", "\"$@\"", "spawn-via-shell", };
475 char **argsp = fargs;
483 if (strEQ(PL_Argv[0],"/bin/sh"))
484 PL_Argv[0] = PL_sh_path;
486 if (PL_Argv[0][0] != '/' && PL_Argv[0][0] != '\\'
487 && !(PL_Argv[0][0] && PL_Argv[0][1] == ':'
488 && (PL_Argv[0][2] == '/' || PL_Argv[0][2] != '\\'))
489 ) /* will spawnvp use PATH? */
490 TAINT_ENV(); /* testing IFS here is overkill, probably */
491 /* We should check PERL_SH* and PERLLIB_* as well? */
492 if (!really || !*(tmps = SvPV(really, PL_na)))
497 if (_emx_env & 0x200) { /* OS/2. */
498 int type = file_type(tmps);
500 if (type == -1) { /* Not found */
505 else if (type == -2) { /* Not an EXE */
510 else if (type == -3) { /* Is a directory? */
511 /* Special-case this */
513 int l = strlen(tmps);
515 if (l + 5 <= sizeof tbuf) {
517 strcpy(tbuf + l, ".exe");
518 type = file_type(tbuf);
528 /* Ignore WINDOWCOMPAT and FAPI, start them the same type we are. */
529 case FAPPTYP_WINDOWAPI:
531 if (os2_mytype != 3) { /* not PM */
532 if (flag == P_NOWAIT)
534 else if ((flag & 7) != P_PM && (flag & 7) != P_SESSION)
535 warn("Starting PM process with flag=%d, mytype=%d",
540 case FAPPTYP_NOTWINDOWCOMPAT:
542 if (os2_mytype != 0) { /* not full screen */
543 if (flag == P_NOWAIT)
545 else if ((flag & 7) != P_SESSION)
546 warn("Starting Full Screen process with flag=%d, mytype=%d",
551 case FAPPTYP_NOTSPEC:
552 /* Let the shell handle this... */
560 rc = result(trueflag, spawnvp(flag,tmps,PL_Argv));
562 if (execf == EXECF_TRUEEXEC)
563 rc = execvp(tmps,PL_Argv);
564 else if (execf == EXECF_EXEC)
565 rc = spawnvp(trueflag | P_OVERLAY,tmps,PL_Argv);
566 else if (execf == EXECF_SPAWN_NOWAIT)
567 rc = spawnvp(flag,tmps,PL_Argv);
568 else /* EXECF_SPAWN */
569 rc = result(trueflag,
570 spawnvp(flag,tmps,PL_Argv));
572 if (rc < 0 && pass == 1
573 && (tmps == PL_Argv[0])) { /* Cannot transfer `really' via shell. */
578 if (err == ENOENT || err == ENOEXEC) {
579 /* No such file, or is a script. */
580 /* Try adding script extensions to the file name, and
582 char *scr = find_script(PL_Argv[0], TRUE, NULL, 0);
585 if (l >= sizeof scrbuf) {
588 croak("Size of scriptname too big: %d", l);
595 FILE *file = fopen(scr, "r");
601 if (!fgets(buf, sizeof buf, file)) { /* Empty... */
605 /* Special case: maybe from -Zexe build, so
606 there is an executable around (contrary to
607 documentation, DosQueryAppType sometimes (?)
608 does not append ".exe", so we could have
609 reached this place). */
610 if (l + 5 < sizeof scrbuf) {
611 strcpy(scrbuf + l, ".exe");
612 if (PerlLIO_stat(scrbuf,&PL_statbuf) >= 0
613 && !S_ISDIR(PL_statbuf.st_mode)) {
623 if (fclose(file) != 0) { /* Failure */
625 warn("Error reading \"%s\": %s",
626 scr, Strerror(errno));
627 buf[0] = 0; /* Not #! */
633 } else if (buf[0] == 'e') {
634 if (strnEQ(buf, "extproc", 7)
637 } else if (buf[0] == 'E') {
638 if (strnEQ(buf, "EXTPROC", 7)
643 buf[0] = 0; /* Not #! */
651 /* Do better than pdksh: allow a few args,
652 strip trailing whitespace. */
662 while (*s && !isSPACE(*s))
669 warn("Too many args on %.*s line of \"%s\"",
680 || (!buf[0] && file)) { /* File without magic */
681 /* In fact we tried all what pdksh would
682 try. There is no point in calling
683 pdksh, we may just emulate its logic. */
684 char *shell = getenv("EXECSHELL");
685 char *shell_opt = NULL;
691 shell = getenv("OS2_SHELL");
692 if (inicmd) { /* No spaces at start! */
694 while (*s && !isSPACE(*s)) {
696 inicmd = NULL; /* Cannot use */
704 /* Dosish shells will choke on slashes
705 in paths, fortunately, this is
706 important for zeroth arg only. */
713 /* If EXECSHELL is set, we do not set */
716 shell = ((_emx_env & 0x200)
719 nargs = shell_opt ? 2 : 1; /* shell file args */
720 exec_args[0] = shell;
721 exec_args[1] = shell_opt;
723 if (nargs == 2 && inicmd) {
724 /* Use the original cmd line */
725 /* XXXX This is good only until we refuse
726 quoted arguments... */
730 } else if (!buf[0] && inicmd) { /* No file */
731 /* Start with the original cmdline. */
732 /* XXXX This is good only until we refuse
733 quoted arguments... */
737 nargs = 2; /* shell -c */
740 while (a[1]) /* Get to the end */
742 a++; /* Copy finil NULL too */
743 while (a >= PL_Argv) {
744 *(a + nargs) = *a; /* PL_Argv was preallocated to be
749 PL_Argv[nargs] = argsp[nargs];
750 /* Enable pathless exec if #! (as pdksh). */
751 pass = (buf[0] == '#' ? 2 : 3);
755 /* Not found: restore errno */
759 } else if (rc < 0 && pass == 2 && errno == ENOENT) { /* File not found */
760 char *no_dir = strrchr(PL_Argv[0], '/');
762 /* Do as pdksh port does: if not found with /, try without
765 PL_Argv[0] = no_dir + 1;
770 if (rc < 0 && PL_dowarn)
771 warn("Can't %s \"%s\": %s\n",
772 ((execf != EXECF_EXEC && execf != EXECF_TRUEEXEC)
774 PL_Argv[0], Strerror(errno));
775 if (rc < 0 && (execf != EXECF_SPAWN_NOWAIT)
776 && ((trueflag & 0xFF) == P_WAIT))
777 rc = 255 << 8; /* Emulate the fork(). */
784 do_aspawn(really,mark,sp)
793 int flag = P_WAIT, trueflag, err, secondtry = 0;
796 New(1301,PL_Argv, sp - mark + 3, char*);
799 if (mark < sp && SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
804 while (++mark <= sp) {
806 *a++ = SvPVx(*mark, PL_na);
812 rc = do_spawn_ve(really, flag, EXECF_SPAWN, NULL);
819 /* Try converting 1-arg form to (usually shell-less) multi-arg form. */
821 do_spawn2(cmd, execf)
828 char *shell, *copt, *news = NULL;
829 int rc, err, seenspace = 0;
830 char fullcmd[MAXNAMLEN + 1];
833 if ((shell = getenv("EMXSHELL")) != NULL)
835 else if ((shell = getenv("SHELL")) != NULL)
837 else if ((shell = getenv("COMSPEC")) != NULL)
842 /* Consensus on perl5-porters is that it is _very_ important to
843 have a shell which will not change between computers with the
844 same architecture, to avoid "action on a distance".
845 And to have simple build, this shell should be sh. */
850 while (*cmd && isSPACE(*cmd))
853 if (strnEQ(cmd,"/bin/sh",7) && isSPACE(cmd[7])) {
854 STRLEN l = strlen(PL_sh_path);
856 New(1302, news, strlen(cmd) - 7 + l + 1, char);
857 strcpy(news, PL_sh_path);
858 strcpy(news + l, cmd + 7);
862 /* save an extra exec if possible */
863 /* see if there are shell metacharacters in it */
865 if (*cmd == '.' && isSPACE(cmd[1]))
868 if (strnEQ(cmd,"exec",4) && isSPACE(cmd[4]))
871 for (s = cmd; *s && isALPHA(*s); s++) ; /* catch VAR=val gizmo */
875 for (s = cmd; *s; s++) {
876 if (*s != ' ' && !isALPHA(*s) && strchr("$&*(){}[]'\";\\|?<>~`\n",*s)) {
877 if (*s == '\n' && s[1] == '\0') {
880 } else if (*s == '\\' && !seenspace) {
881 continue; /* Allow backslashes in names */
883 /* We do not convert this to do_spawn_ve since shell
884 should be smart enough to start itself gloriously. */
886 if (execf == EXECF_TRUEEXEC)
887 rc = execl(shell,shell,copt,cmd,(char*)0);
888 else if (execf == EXECF_EXEC)
889 rc = spawnl(P_OVERLAY,shell,shell,copt,cmd,(char*)0);
890 else if (execf == EXECF_SPAWN_NOWAIT)
891 rc = spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0);
893 /* In the ak code internal P_NOWAIT is P_WAIT ??? */
895 spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0));
896 if (rc < 0 && PL_dowarn)
897 warn("Can't %s \"%s\": %s",
898 (execf == EXECF_SPAWN ? "spawn" : "exec"),
899 shell, Strerror(errno));
900 if (rc < 0) rc = 255 << 8; /* Emulate the fork(). */
905 } else if (*s == ' ' || *s == '\t') {
910 /* cmd="a" may lead to "sh", "-c", "\"$@\"", "a", "a.cmd", NULL */
911 New(1303,PL_Argv, (s - cmd + 11) / 2, char*);
912 PL_Cmd = savepvn(cmd, s-cmd);
914 for (s = PL_Cmd; *s;) {
915 while (*s && isSPACE(*s)) s++;
918 while (*s && !isSPACE(*s)) s++;
924 rc = do_spawn_ve(NULL, 0, execf, cmd);
937 return do_spawn2(cmd, EXECF_SPAWN);
944 return do_spawn2(cmd, EXECF_SPAWN_NOWAIT);
951 do_spawn2(cmd, EXECF_EXEC);
959 return do_spawn2(cmd, EXECF_TRUEEXEC);
963 my_syspopen(cmd,mode)
970 register I32 this, that, newfd;
971 register I32 pid, rc;
975 /* `this' is what we use in the parent, `that' in the child. */
976 this = (*mode == 'w');
980 taint_proper("Insecure %s%s", "EXEC");
984 /* Now we need to spawn the child. */
985 newfd = dup(*mode == 'r'); /* Preserve std* */
986 if (p[that] != (*mode == 'r')) {
987 dup2(p[that], *mode == 'r');
990 /* Where is `this' and newfd now? */
991 fcntl(p[this], F_SETFD, FD_CLOEXEC);
992 fcntl(newfd, F_SETFD, FD_CLOEXEC);
993 pid = do_spawn_nowait(cmd);
994 if (newfd != (*mode == 'r')) {
995 dup2(newfd, *mode == 'r'); /* Return std* back. */
998 if (p[that] == (*mode == 'r'))
1004 if (p[that] < p[this]) {
1005 dup2(p[this], p[that]);
1009 sv = *av_fetch(PL_fdpid,p[this],TRUE);
1010 (void)SvUPGRADE(sv,SVt_IV);
1012 PL_forkprocess = pid;
1013 return PerlIO_fdopen(p[this], mode);
1015 #else /* USE_POPEN */
1021 res = popen(cmd, mode);
1023 char *shell = getenv("EMXSHELL");
1025 my_setenv("EMXSHELL", PL_sh_path);
1026 res = popen(cmd, mode);
1027 my_setenv("EMXSHELL", shell);
1029 sv = *av_fetch(PL_fdpid, PerlIO_fileno(res), TRUE);
1030 (void)SvUPGRADE(sv,SVt_IV);
1031 SvIVX(sv) = -1; /* A cooky. */
1034 #endif /* USE_POPEN */
1038 /******************************************************************/
1044 croak(PL_no_func, "Unsupported function fork");
1050 /*******************************************************************/
1051 /* not implemented in EMX 0.9a */
1053 void * ctermid(x) { return 0; }
1055 #ifdef MYTTYNAME /* was not in emx0.9a */
1056 void * ttyname(x) { return 0; }
1059 /******************************************************************/
1060 /* my socket forwarders - EMX lib only provides static forwarders */
1062 static HMODULE htcp = 0;
1067 static BYTE buf[20];
1070 if (!(_emx_env & 0x200)) croak("%s requires OS/2", name); /* Die if not OS/2. */
1072 DosLoadModule(buf, sizeof buf, "tcp32dll", &htcp);
1073 if (htcp && DosQueryProcAddr(htcp, 0, name, &fcn) == 0)
1074 return (void *) ((void * (*)(void)) fcn) ();
1079 tcp1(char *name, int arg)
1081 static BYTE buf[20];
1084 if (!(_emx_env & 0x200)) croak("%s requires OS/2", name); /* Die if not OS/2. */
1086 DosLoadModule(buf, sizeof buf, "tcp32dll", &htcp);
1087 if (htcp && DosQueryProcAddr(htcp, 0, name, &fcn) == 0)
1088 ((void (*)(int)) fcn) (arg);
1091 void * gethostent() { return tcp0("GETHOSTENT"); }
1092 void * getnetent() { return tcp0("GETNETENT"); }
1093 void * getprotoent() { return tcp0("GETPROTOENT"); }
1094 void * getservent() { return tcp0("GETSERVENT"); }
1095 void sethostent(x) { tcp1("SETHOSTENT", x); }
1096 void setnetent(x) { tcp1("SETNETENT", x); }
1097 void setprotoent(x) { tcp1("SETPROTOENT", x); }
1098 void setservent(x) { tcp1("SETSERVENT", x); }
1099 void endhostent() { tcp0("ENDHOSTENT"); }
1100 void endnetent() { tcp0("ENDNETENT"); }
1101 void endprotoent() { tcp0("ENDPROTOENT"); }
1102 void endservent() { tcp0("ENDSERVENT"); }
1104 /*****************************************************************************/
1105 /* not implemented in C Set++ */
1108 int setuid(x) { errno = EINVAL; return -1; }
1109 int setgid(x) { errno = EINVAL; return -1; }
1112 /*****************************************************************************/
1113 /* stat() hack for char/block device */
1117 /* First attempt used DosQueryFSAttach which crashed the system when
1118 used with 5.001. Now just look for /dev/. */
1121 os2_stat(char *name, struct stat *st)
1123 static int ino = SHRT_MAX;
1125 if (stricmp(name, "/dev/con") != 0
1126 && stricmp(name, "/dev/tty") != 0)
1127 return stat(name, st);
1129 memset(st, 0, sizeof *st);
1130 st->st_mode = S_IFCHR|0666;
1131 st->st_ino = (ino-- & 0x7FFF);
1138 #ifdef USE_PERL_SBRK
1140 /* SBRK() emulation, mostly moved to malloc.c. */
1143 sys_alloc(int size) {
1145 APIRET rc = DosAllocMem(&got, size, PAG_COMMIT | PAG_WRITE);
1147 if (rc == ERROR_NOT_ENOUGH_MEMORY) {
1150 croak("Got an error from DosAllocMem: %li", (long)rc);
1154 #endif /* USE_PERL_SBRK */
1158 char *tmppath = TMPPATH1;
1163 char *p = getenv("TMP"), *tpath;
1166 if (!p) p = getenv("TEMP");
1169 tpath = (char *)malloc(len + strlen(TMPPATH1) + 2);
1172 strcpy(tpath + len + 1, TMPPATH1);
1178 XS(XS_File__Copy_syscopy)
1181 if (items < 2 || items > 3)
1182 croak("Usage: File::Copy::syscopy(src,dst,flag=0)");
1184 char * src = (char *)SvPV(ST(0),PL_na);
1185 char * dst = (char *)SvPV(ST(1),PL_na);
1192 flag = (unsigned long)SvIV(ST(2));
1195 RETVAL = !CheckOSError(DosCopy(src, dst, flag));
1196 ST(0) = sv_newmortal();
1197 sv_setiv(ST(0), (IV)RETVAL);
1202 #include "patchlevel.h"
1208 static char fname[9];
1209 int pos = 6, len, avlen;
1210 unsigned int sum = 0;
1215 if (!SvROK(sv)) croak("Not a reference given to mod2fname");
1217 if (SvTYPE(sv) != SVt_PVAV)
1218 croak("Not array reference given to mod2fname");
1220 avlen = av_len((AV*)sv);
1222 croak("Empty array reference given to mod2fname");
1224 s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), PL_na);
1225 strncpy(fname, s, 8);
1227 if (len < 6) pos = len;
1229 sum = 33 * sum + *(s++); /* Checksumming first chars to
1230 * get the capitalization into c.s. */
1233 while (avlen >= 0) {
1234 s = SvPV(*av_fetch((AV*)sv, avlen, FALSE), PL_na);
1236 sum = 33 * sum + *(s++); /* 7 is primitive mod 13. */
1241 sum++; /* Avoid conflict of DLLs in memory. */
1243 sum += PATCHLEVEL * 200 + SUBVERSION * 2; /* */
1244 fname[pos] = 'A' + (sum % 26);
1245 fname[pos + 1] = 'A' + (sum / 26 % 26);
1246 fname[pos + 2] = '\0';
1247 return (char *)fname;
1250 XS(XS_DynaLoader_mod2fname)
1254 croak("Usage: DynaLoader::mod2fname(sv)");
1259 RETVAL = mod2fname(sv);
1260 ST(0) = sv_newmortal();
1261 sv_setpv((SV*)ST(0), RETVAL);
1269 static char buf[300];
1272 if (!(_emx_env & 0x200)) return ""; /* Nop if not OS/2. */
1275 if (DosGetMessage(NULL, 0, buf, sizeof buf - 1, rc, "OSO001.MSG", &len))
1276 sprintf(buf, "OS/2 system error code %d=0x%x", rc, rc);
1279 if (len > 0 && buf[len - 1] == '\n')
1280 buf[len - 1] = '\0';
1281 if (len > 1 && buf[len - 2] == '\r')
1282 buf[len - 2] = '\0';
1283 if (len > 2 && buf[len - 3] == '.')
1284 buf[len - 3] = '\0';
1289 perllib_mangle(char *s, unsigned int l)
1291 static char *newp, *oldp;
1292 static int newl, oldl, notfound;
1293 static char ret[STATIC_FILE_LENGTH+1];
1295 if (!newp && !notfound) {
1296 newp = getenv("PERLLIB_PREFIX");
1301 while (*newp && !isSPACE(*newp) && *newp != ';') {
1302 newp++; oldl++; /* Skip digits. */
1304 while (*newp && (isSPACE(*newp) || *newp == ';')) {
1305 newp++; /* Skip whitespace. */
1307 newl = strlen(newp);
1308 if (newl == 0 || oldl == 0) {
1309 croak("Malformed PERLLIB_PREFIX");
1314 if (*s == '\\') *s = '/';
1327 if (l < oldl || strnicmp(oldp, s, oldl) != 0) {
1330 if (l + newl - oldl > STATIC_FILE_LENGTH || newl > STATIC_FILE_LENGTH) {
1331 croak("Malformed PERLLIB_PREFIX");
1333 strcpy(ret + newl, s + oldl);
1338 Perl_hab_GET() /* Needed if perl.h cannot be included */
1340 return perl_hab_GET();
1344 Perl_Register_MQ(int serve)
1349 if (Perl_os2_initial_mode++)
1351 DosGetInfoBlocks(&tib, &pib);
1352 Perl_os2_initial_mode = pib->pib_ultype;
1353 Perl_hmq_refcnt = 1;
1354 /* Try morphing into a PM application. */
1355 if (pib->pib_ultype != 3) /* 2 is VIO */
1356 pib->pib_ultype = 3; /* 3 is PM */
1357 init_PMWIN_entries();
1358 /* 64 messages if before OS/2 3.0, ignored otherwise */
1359 Perl_hmq = (*PMWIN_entries.CreateMsgQueue)(perl_hab_GET(), 64);
1363 _exit(188); /* Panic can try to create a window. */
1364 croak("Cannot create a message queue, or morph to a PM application");
1370 Perl_Serve_Messages(int force)
1375 if (Perl_hmq_servers && !force)
1377 if (!Perl_hmq_refcnt)
1378 croak("No message queue");
1379 while ((*PMWIN_entries.PeekMsg)(Perl_hab, &msg, NULLHANDLE, 0, 0, PM_REMOVE)) {
1381 if (msg.msg == WM_QUIT)
1382 croak("QUITing...");
1383 (*PMWIN_entries.DispatchMsg)(Perl_hab, &msg);
1389 Perl_Process_Messages(int force, I32 *cntp)
1393 if (Perl_hmq_servers && !force)
1395 if (!Perl_hmq_refcnt)
1396 croak("No message queue");
1397 while ((*PMWIN_entries.GetMsg)(Perl_hab, &msg, NULLHANDLE, 0, 0)) {
1400 (*PMWIN_entries.DispatchMsg)(Perl_hab, &msg);
1401 if (msg.msg == WM_DESTROY)
1403 if (msg.msg == WM_CREATE)
1406 croak("QUITing...");
1410 Perl_Deregister_MQ(int serve)
1415 if (--Perl_hmq_refcnt == 0) {
1416 (*PMWIN_entries.DestroyMsgQueue)(Perl_hmq);
1418 /* Try morphing back from a PM application. */
1419 if (pib->pib_ultype == 3) /* 3 is PM */
1420 pib->pib_ultype = Perl_os2_initial_mode;
1422 warn("Unexpected program mode %d when morphing back from PM",
1427 extern void dlopen();
1428 void *fakedl = &dlopen; /* Pull in dynaloading part. */
1430 #define sys_is_absolute(path) ( isALPHA((path)[0]) && (path)[1] == ':' \
1431 && ((path)[2] == '/' || (path)[2] == '\\'))
1432 #define sys_is_rooted _fnisabs
1433 #define sys_is_relative _fnisrel
1434 #define current_drive _getdrive
1436 #undef chdir /* Was _chdir2. */
1437 #define sys_chdir(p) (chdir(p) == 0)
1438 #define change_drive(d) (_chdrive(d), (current_drive() == toupper(d)))
1440 static int DOS_harderr_state = -1;
1446 croak("Usage: OS2::Error(harderr, exception)");
1448 int arg1 = SvIV(ST(0));
1449 int arg2 = SvIV(ST(1));
1450 int a = ((arg1 ? FERR_ENABLEHARDERR : FERR_DISABLEHARDERR)
1451 | (arg2 ? FERR_ENABLEEXCEPTION : FERR_DISABLEEXCEPTION));
1452 int RETVAL = ((arg1 ? 1 : 0) | (arg2 ? 2 : 0));
1455 if (CheckOSError(DosError(a)))
1456 croak("DosError(%d) failed", a);
1457 ST(0) = sv_newmortal();
1458 if (DOS_harderr_state >= 0)
1459 sv_setiv(ST(0), DOS_harderr_state);
1460 DOS_harderr_state = RETVAL;
1465 static signed char DOS_suppression_state = -1;
1467 XS(XS_OS2_Errors2Drive)
1471 croak("Usage: OS2::Errors2Drive(drive)");
1474 int suppress = SvOK(sv);
1475 char *s = suppress ? SvPV(sv, PL_na) : NULL;
1476 char drive = (s ? *s : 0);
1479 if (suppress && !isALPHA(drive))
1480 croak("Non-char argument '%c' to OS2::Errors2Drive()", drive);
1481 if (CheckOSError(DosSuppressPopUps((suppress
1482 ? SPU_ENABLESUPPRESSION
1483 : SPU_DISABLESUPPRESSION),
1485 croak("DosSuppressPopUps(%c) failed", drive);
1486 ST(0) = sv_newmortal();
1487 if (DOS_suppression_state > 0)
1488 sv_setpvn(ST(0), &DOS_suppression_state, 1);
1489 else if (DOS_suppression_state == 0)
1490 sv_setpvn(ST(0), "", 0);
1491 DOS_suppression_state = drive;
1496 static const char * const si_fields[QSV_MAX] = {
1498 "MAX_TEXT_SESSIONS",
1502 "DYN_PRI_VARIATION",
1520 "FOREGROUND_FS_SESSION",
1521 "FOREGROUND_PROCESS"
1528 croak("Usage: OS2::SysInfo()");
1530 ULONG si[QSV_MAX] = {0}; /* System Information Data Buffer */
1531 APIRET rc = NO_ERROR; /* Return code */
1534 if (CheckOSError(DosQuerySysInfo(1L, /* Request all available system */
1535 QSV_MAX, /* information */
1538 croak("DosQuerySysInfo() failed");
1539 EXTEND(SP,2*QSV_MAX);
1540 while (i < QSV_MAX) {
1541 ST(j) = sv_newmortal();
1542 sv_setpv(ST(j++), si_fields[i]);
1543 ST(j) = sv_newmortal();
1544 sv_setiv(ST(j++), si[i]);
1548 XSRETURN(2 * QSV_MAX);
1551 XS(XS_OS2_BootDrive)
1555 croak("Usage: OS2::BootDrive()");
1557 ULONG si[1] = {0}; /* System Information Data Buffer */
1558 APIRET rc = NO_ERROR; /* Return code */
1561 if (CheckOSError(DosQuerySysInfo(QSV_BOOT_DRIVE, QSV_BOOT_DRIVE,
1562 (PVOID)si, sizeof(si))))
1563 croak("DosQuerySysInfo() failed");
1564 ST(0) = sv_newmortal();
1565 c = 'a' - 1 + si[0];
1566 sv_setpvn(ST(0), &c, 1);
1575 croak("Usage: OS2::MorphPM(serve)");
1577 bool serve = SvOK(ST(0));
1578 unsigned long pmq = perl_hmq_GET(serve);
1580 ST(0) = sv_newmortal();
1581 sv_setiv(ST(0), pmq);
1586 XS(XS_OS2_UnMorphPM)
1590 croak("Usage: OS2::UnMorphPM(serve)");
1592 bool serve = SvOK(ST(0));
1594 perl_hmq_UNSET(serve);
1599 XS(XS_OS2_Serve_Messages)
1603 croak("Usage: OS2::Serve_Messages(force)");
1605 bool force = SvOK(ST(0));
1606 unsigned long cnt = Perl_Serve_Messages(force);
1608 ST(0) = sv_newmortal();
1609 sv_setiv(ST(0), cnt);
1614 XS(XS_OS2_Process_Messages)
1617 if (items < 1 || items > 2)
1618 croak("Usage: OS2::Process_Messages(force [, cnt])");
1620 bool force = SvOK(ST(0));
1626 int fake = SvIV(sv); /* Force SvIVX */
1629 croak("Can't upgrade count to IV");
1632 cnt = Perl_Process_Messages(force, cntp);
1633 ST(0) = sv_newmortal();
1634 sv_setiv(ST(0), cnt);
1639 XS(XS_Cwd_current_drive)
1643 croak("Usage: Cwd::current_drive()");
1647 RETVAL = current_drive();
1648 ST(0) = sv_newmortal();
1649 sv_setpvn(ST(0), (char *)&RETVAL, 1);
1654 XS(XS_Cwd_sys_chdir)
1658 croak("Usage: Cwd::sys_chdir(path)");
1660 char * path = (char *)SvPV(ST(0),PL_na);
1663 RETVAL = sys_chdir(path);
1664 ST(0) = boolSV(RETVAL);
1665 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1670 XS(XS_Cwd_change_drive)
1674 croak("Usage: Cwd::change_drive(d)");
1676 char d = (char)*SvPV(ST(0),PL_na);
1679 RETVAL = change_drive(d);
1680 ST(0) = boolSV(RETVAL);
1681 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1686 XS(XS_Cwd_sys_is_absolute)
1690 croak("Usage: Cwd::sys_is_absolute(path)");
1692 char * path = (char *)SvPV(ST(0),PL_na);
1695 RETVAL = sys_is_absolute(path);
1696 ST(0) = boolSV(RETVAL);
1697 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1702 XS(XS_Cwd_sys_is_rooted)
1706 croak("Usage: Cwd::sys_is_rooted(path)");
1708 char * path = (char *)SvPV(ST(0),PL_na);
1711 RETVAL = sys_is_rooted(path);
1712 ST(0) = boolSV(RETVAL);
1713 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1718 XS(XS_Cwd_sys_is_relative)
1722 croak("Usage: Cwd::sys_is_relative(path)");
1724 char * path = (char *)SvPV(ST(0),PL_na);
1727 RETVAL = sys_is_relative(path);
1728 ST(0) = boolSV(RETVAL);
1729 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1738 croak("Usage: Cwd::sys_cwd()");
1742 RETVAL = _getcwd2(p, MAXPATHLEN);
1743 ST(0) = sv_newmortal();
1744 sv_setpv((SV*)ST(0), RETVAL);
1749 XS(XS_Cwd_sys_abspath)
1752 if (items < 1 || items > 2)
1753 croak("Usage: Cwd::sys_abspath(path, dir = NULL)");
1755 char * path = (char *)SvPV(ST(0),PL_na);
1763 dir = (char *)SvPV(ST(1),PL_na);
1765 if (path[0] == '.' && (path[1] == '/' || path[1] == '\\')) {
1769 if (_abspath(p, path, MAXPATHLEN) == 0) {
1775 /* Absolute with drive: */
1776 if ( sys_is_absolute(path) ) {
1777 if (_abspath(p, path, MAXPATHLEN) == 0) {
1782 } else if (path[0] == '/' || path[0] == '\\') {
1783 /* Rooted, but maybe on different drive. */
1784 if (isALPHA(dir[0]) && dir[1] == ':' ) {
1785 char p1[MAXPATHLEN];
1787 /* Need to prepend the drive. */
1790 Copy(path, p1 + 2, strlen(path) + 1, char);
1792 if (_abspath(p, p1, MAXPATHLEN) == 0) {
1797 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
1803 /* Either path is relative, or starts with a drive letter. */
1804 /* If the path starts with a drive letter, then dir is
1806 a/b) it is absolute/x:relative on the same drive.
1807 c) path is on current drive, and dir is rooted
1808 In all the cases it is safe to drop the drive part
1810 if ( !sys_is_relative(path) ) {
1813 if ( ( ( sys_is_absolute(dir)
1814 || (isALPHA(dir[0]) && dir[1] == ':'
1815 && strnicmp(dir, path,1) == 0))
1816 && strnicmp(dir, path,1) == 0)
1817 || ( !(isALPHA(dir[0]) && dir[1] == ':')
1818 && toupper(path[0]) == current_drive())) {
1820 } else if (_abspath(p, path, MAXPATHLEN) == 0) {
1821 RETVAL = p; goto done;
1823 RETVAL = NULL; goto done;
1827 /* Need to prepend the absolute path of dir. */
1828 char p1[MAXPATHLEN];
1830 if (_abspath(p1, dir, MAXPATHLEN) == 0) {
1833 if (p1[ l - 1 ] != '/') {
1837 Copy(path, p1 + l, strlen(path) + 1, char);
1838 if (_abspath(p, p1, MAXPATHLEN) == 0) {
1850 ST(0) = sv_newmortal();
1851 sv_setpv((SV*)ST(0), RETVAL);
1855 typedef APIRET (*PELP)(PSZ path, ULONG type);
1858 ExtLIBPATH(ULONG ord, PSZ path, ULONG type)
1860 loadByOrd("doscalls",ord); /* Guarantied to load or die! */
1861 return (*(PELP)ExtFCN[ord])(path, type);
1864 #define extLibpath(type) \
1865 (CheckOSError(ExtLIBPATH(ORD_QUERY_ELP, to, ((type) ? END_LIBPATH \
1866 : BEGIN_LIBPATH))) \
1869 #define extLibpath_set(p,type) \
1870 (!CheckOSError(ExtLIBPATH(ORD_SET_ELP, (p), ((type) ? END_LIBPATH \
1873 XS(XS_Cwd_extLibpath)
1876 if (items < 0 || items > 1)
1877 croak("Usage: Cwd::extLibpath(type = 0)");
1887 type = (int)SvIV(ST(0));
1890 RETVAL = extLibpath(type);
1891 ST(0) = sv_newmortal();
1892 sv_setpv((SV*)ST(0), RETVAL);
1897 XS(XS_Cwd_extLibpath_set)
1900 if (items < 1 || items > 2)
1901 croak("Usage: Cwd::extLibpath_set(s, type = 0)");
1903 char * s = (char *)SvPV(ST(0),PL_na);
1911 type = (int)SvIV(ST(1));
1914 RETVAL = extLibpath_set(s, type);
1915 ST(0) = boolSV(RETVAL);
1916 if (SvREFCNT(ST(0))) sv_2mortal(ST(0));
1924 char *file = __FILE__;
1928 if (_emx_env & 0x200) { /* OS/2 */
1929 newXS("File::Copy::syscopy", XS_File__Copy_syscopy, file);
1930 newXS("Cwd::extLibpath", XS_Cwd_extLibpath, file);
1931 newXS("Cwd::extLibpath_set", XS_Cwd_extLibpath_set, file);
1933 newXS("OS2::Error", XS_OS2_Error, file);
1934 newXS("OS2::Errors2Drive", XS_OS2_Errors2Drive, file);
1935 newXS("OS2::SysInfo", XS_OS2_SysInfo, file);
1936 newXS("OS2::BootDrive", XS_OS2_BootDrive, file);
1937 newXS("OS2::MorphPM", XS_OS2_MorphPM, file);
1938 newXS("OS2::UnMorphPM", XS_OS2_UnMorphPM, file);
1939 newXS("OS2::Serve_Messages", XS_OS2_Serve_Messages, file);
1940 newXS("OS2::Process_Messages", XS_OS2_Process_Messages, file);
1941 newXS("DynaLoader::mod2fname", XS_DynaLoader_mod2fname, file);
1942 newXS("Cwd::current_drive", XS_Cwd_current_drive, file);
1943 newXS("Cwd::sys_chdir", XS_Cwd_sys_chdir, file);
1944 newXS("Cwd::change_drive", XS_Cwd_change_drive, file);
1945 newXS("Cwd::sys_is_absolute", XS_Cwd_sys_is_absolute, file);
1946 newXS("Cwd::sys_is_rooted", XS_Cwd_sys_is_rooted, file);
1947 newXS("Cwd::sys_is_relative", XS_Cwd_sys_is_relative, file);
1948 newXS("Cwd::sys_cwd", XS_Cwd_sys_cwd, file);
1949 newXS("Cwd::sys_abspath", XS_Cwd_sys_abspath, file);
1950 gv = gv_fetchpv("OS2::is_aout", TRUE, SVt_PV);
1953 sv_setiv(GvSV(gv), 1);
1955 gv = gv_fetchpv("OS2::emx_rev", TRUE, SVt_PV);
1957 sv_setiv(GvSV(gv), _emx_rev);
1958 sv_setpv(GvSV(gv), _emx_vprt);
1960 gv = gv_fetchpv("OS2::emx_env", TRUE, SVt_PV);
1962 sv_setiv(GvSV(gv), _emx_env);
1963 gv = gv_fetchpv("OS2::os_ver", TRUE, SVt_PV);
1965 sv_setnv(GvSV(gv), _osmajor + 0.001 * _osminor);
1969 OS2_Perl_data_t OS2_Perl_data;
1972 Perl_OS2_init(char **env)
1978 OS2_Perl_data.xs_init = &Xs_OS2_init;
1979 _uflags (_UF_SBRK_MODEL, _UF_SBRK_ARBITRARY);
1980 if (environ == NULL) {
1983 if ( (shell = getenv("PERL_SH_DRIVE")) ) {
1984 New(1304, PL_sh_path, strlen(SH_PATH) + 1, char);
1985 strcpy(PL_sh_path, SH_PATH);
1986 PL_sh_path[0] = shell[0];
1987 } else if ( (shell = getenv("PERL_SH_DIR")) ) {
1988 int l = strlen(shell), i;
1989 if (shell[l-1] == '/' || shell[l-1] == '\\') {
1992 New(1304, PL_sh_path, l + 8, char);
1993 strncpy(PL_sh_path, shell, l);
1994 strcpy(PL_sh_path + l, "/sh.exe");
1995 for (i = 0; i < l; i++) {
1996 if (PL_sh_path[i] == '\\') PL_sh_path[i] = '/';
1999 MUTEX_INIT(&start_thread_mutex);
2000 os2_mytype = my_type(); /* Do it before morphing. Needed? */
2007 my_tmpnam (char *str)
2009 char *p = getenv("TMP"), *tpath;
2012 if (!p) p = getenv("TEMP");
2013 tpath = tempnam(p, "pltmp");
2027 if (s.st_mode & S_IWOTH) {
2030 return fopen(my_tmpnam(NULL), "w+b"); /* Race condition, but
2036 /* This code was contributed by Rocco Caputo. */
2038 my_flock(int handle, int o)
2040 FILELOCK rNull, rFull;
2041 ULONG timeout, handle_type, flag_word;
2043 int blocking, shared;
2044 static int use_my = -1;
2047 char *s = getenv("USE_PERL_FLOCK");
2053 if (!(_emx_env & 0x200) || !use_my)
2054 return flock(handle, o); /* Delegate to EMX. */
2057 if ((DosQueryHType(handle, &handle_type, &flag_word) != 0) ||
2058 (handle_type & 0xFF))
2063 // set lock/unlock ranges
2064 rNull.lOffset = rNull.lRange = rFull.lOffset = 0;
2065 rFull.lRange = 0x7FFFFFFF;
2066 // set timeout for blocking
2067 timeout = ((blocking = !(o & LOCK_NB))) ? 100 : 1;
2068 // shared or exclusive?
2069 shared = (o & LOCK_SH) ? 1 : 0;
2070 // do not block the unlock
2071 if (o & (LOCK_UN | LOCK_SH | LOCK_EX)) {
2072 rc = DosSetFileLocks(handle, &rFull, &rNull, timeout, shared);
2077 case ERROR_INVALID_HANDLE:
2080 case ERROR_SHARING_BUFFER_EXCEEDED:
2083 case ERROR_LOCK_VIOLATION:
2084 break; // not an error
2085 case ERROR_INVALID_PARAMETER:
2086 case ERROR_ATOMIC_LOCK_NOT_SUPPORTED:
2087 case ERROR_READ_LOCKS_NOT_SUPPORTED:
2090 case ERROR_INTERRUPT:
2099 if (o & (LOCK_SH | LOCK_EX)) {
2100 // for blocking operations
2114 case ERROR_INVALID_HANDLE:
2117 case ERROR_SHARING_BUFFER_EXCEEDED:
2120 case ERROR_LOCK_VIOLATION:
2122 errno = EWOULDBLOCK;
2126 case ERROR_INVALID_PARAMETER:
2127 case ERROR_ATOMIC_LOCK_NOT_SUPPORTED:
2128 case ERROR_READ_LOCKS_NOT_SUPPORTED:
2131 case ERROR_INTERRUPT:
2138 // give away timeslice