FreeBSD support
[lcore.git] / lcoreselect.pas
old mode 100755 (executable)
new mode 100644 (file)
index feb8ef8..d3685ae
@@ -45,10 +45,10 @@ uses
 {$include unixstuff.inc}\r
 \r
 const\r
 {$include unixstuff.inc}\r
 \r
 const\r
-  absoloutemaxs_select = (sizeof(fdset)*8)-1;\r
+  absolutemaxs_select = (sizeof(fdset)*8)-1;\r
 \r
 var\r
 \r
 var\r
-  fdreverse:array[0..absoloutemaxs_select] of tlasio;\r
+  fdreverse:array[0..absolutemaxs_select] of tlasio;\r
 type\r
   tselecteventcore=class(teventcore)\r
     public\r
 type\r
   tselecteventcore=class(teventcore)\r
     public\r
@@ -64,12 +64,12 @@ type
 \r
 procedure processtimers;inline;\r
 var\r
 \r
 procedure processtimers;inline;\r
 var\r
-  tv           ,tvnow     : ttimeval ;\r
+  tvnow     : ttimeval ;\r
   currenttimer            : tltimer   ;\r
   temptimer               : tltimer  ;\r
 \r
 begin\r
   currenttimer            : tltimer   ;\r
   temptimer               : tltimer  ;\r
 \r
 begin\r
-  gettimeofday(tvnow);\r
+  gettimemonotonic(tvnow);\r
   currenttimer := firsttimer;\r
   while assigned(currenttimer) do begin\r
     //writeln(currenttimer.enabled);\r
   currenttimer := firsttimer;\r
   while assigned(currenttimer) do begin\r
     //writeln(currenttimer.enabled);\r
@@ -90,24 +90,25 @@ end;
 procedure processasios(var fdsr,fdsw:fdset);//inline;\r
 var\r
   currentsocket : tlasio  ;\r
 procedure processasios(var fdsr,fdsw:fdset);//inline;\r
 var\r
   currentsocket : tlasio  ;\r
-  tempsocket    : tlasio  ;\r
-  socketcount   : integer ; // for debugging perposes :)\r
+  socketcount   : integer ; // for debugging purposes :)\r
   dw,bt:integer;\r
   dw,bt:integer;\r
+  currentfdword:fdword;\r
   fd : integer;\r
 begin\r
   //writeln('entering processasios');\r
 {  inc(lcoretestcount);}\r
 \r
   fd : integer;\r
 begin\r
   //writeln('entering processasios');\r
 {  inc(lcoretestcount);}\r
 \r
-    //the message loop will exit if all lasio's and ltimer's and lsignal's are destroyed\r
+    //the message loop will exit if all lasios and ltimers and lsignals are destroyed\r
     //if (not assigned(firstasin)) and (not assigned(firsttimer)) and (not assigned(firstsignal)) then exit;\r
 \r
 \r
   {------- test optimised loop}\r
   socketcount := 0;\r
     //if (not assigned(firstasin)) and (not assigned(firsttimer)) and (not assigned(firstsignal)) then exit;\r
 \r
 \r
   {------- test optimised loop}\r
   socketcount := 0;\r
-  for dw := (maxs shr 5) downto 0 do if (fdsr[dw] or fdsw[dw]) <> 0 then begin\r
-    for bt := 0 to 31 do if (fdsr[dw] or fdsw[dw]) and (1 shl bt) <> 0 then begin\r
+  for dw := (maxs shr fdwordshift) downto 0 do if (fdsr[dw] or fdsw[dw]) <> 0 then begin\r
+    currentfdword := (fdsr[dw] or fdsw[dw]);\r
+    for bt := fdwordmaxbit downto 0 do if currentfdword and (1 shl bt) <> 0 then begin\r
       inc(socketcount);\r
       inc(socketcount);\r
-      fd := dw shl 5 or bt;\r
+      fd := dw shl fdwordshift or bt;\r
       //writeln('reversing fd ',fd);\r
       currentsocket := fdreverse[fd];\r
       {if not assigned(currentsocket) then raise exception.create('currentsocket not assigned');\r
       //writeln('reversing fd ',fd);\r
       currentsocket := fdreverse[fd];\r
       {if not assigned(currentsocket) then raise exception.create('currentsocket not assigned');\r
@@ -143,7 +144,7 @@ begin
   - sockets which are released may not be freed because theyre never processed by the loop\r
   made new code for handling this, using asinreleaseflag\r
 \r
   - sockets which are released may not be freed because theyre never processed by the loop\r
   made new code for handling this, using asinreleaseflag\r
 \r
-  - when/why does the mustrefreshfds select apply, sheck if i did it correctly?\r
+  - when/why does the mustrefreshfds select apply, check if i did it correctly?\r
 \r
   - what happens if calling handlefdtrigger for a socket which does not have an event\r
   }\r
 \r
   - what happens if calling handlefdtrigger for a socket which does not have an event\r
   }\r
@@ -189,7 +190,7 @@ begin
     prepsigpipe;\r
   {$endif}\r
   selectresult := select(maxs+1,@fdsr,@fdsw,nil,0);\r
     prepsigpipe;\r
   {$endif}\r
   selectresult := select(maxs+1,@fdsr,@fdsw,nil,0);\r
-  while (selectresult>0) or assigned(firsttask) or assigned(currenttask) do begin;\r
+  while (selectresult>0) or assigned(firsttask) do begin;\r
 \r
     processtasks;\r
     processtimers;\r
 \r
     processtasks;\r
     processtimers;\r
@@ -219,10 +220,22 @@ begin
 end;\r
 \r
 \r
 end;\r
 \r
 \r
+{\r
+select in linux/sysV subtracts from timeout for time spent in it, but in BSD it doesn't\r
+enabling select_no_autotv here makes doSelect mimic the decrement behavior, in case the caller needs it\r
+the caller here in lcoreselect does not need it, and enabling it would have a slight perf hit.\r
+it is safe for this to be enabled even if the OS does it too (it will not subtract twice)\r
+it is currently disabled but can be enabled if needed\r
+}\r
+{$ifndef linux}{-$define select_no_autotv}{$endif}\r
+\r
 Function  doSelect(timeOut:PTimeVal):longint;//inline;\r
 var\r
   localtimeval : ttimeval;\r
   maxslocal    : integer;\r
 Function  doSelect(timeOut:PTimeVal):longint;//inline;\r
 var\r
   localtimeval : ttimeval;\r
   maxslocal    : integer;\r
+  {$ifdef select_no_autotv}\r
+  timeoutcopy,tvstart,tvend : ttimeval;\r
+  {$endif}\r
 begin\r
   //unblock signals\r
   //zeromemory(@sset,sizeof(sset));\r
 begin\r
   //unblock signals\r
   //zeromemory(@sset,sizeof(sset));\r
@@ -242,18 +255,46 @@ begin
   {$ifndef nosignal}\r
     sigprocmask(SIG_UNBLOCK,@blockset,nil);\r
   {$endif}\r
   {$ifndef nosignal}\r
     sigprocmask(SIG_UNBLOCK,@blockset,nil);\r
   {$endif}\r
+\r
+  {$ifdef select_no_autotv}\r
+  if assigned(timeout) then begin\r
+    timeoutcopy.tv_sec := timeOut.tv_sec;\r
+    timeoutcopy.tv_usec := timeOut.tv_usec;\r
+    gettimemonotonic(tvstart);\r
+  end;\r
+  {$endif}\r
+\r
   result := select(maxslocal+1,@FDSR,@FDSW,nil,timeout);\r
   if result <= 0 then begin\r
     fd_zero(FDSR);\r
     fd_zero(FDSW);\r
     if result=-1 then begin\r
       if linuxerror = SYS_EINTR then begin\r
   result := select(maxslocal+1,@FDSR,@FDSW,nil,timeout);\r
   if result <= 0 then begin\r
     fd_zero(FDSR);\r
     fd_zero(FDSW);\r
     if result=-1 then begin\r
       if linuxerror = SYS_EINTR then begin\r
-        // we received a signal it's not a problem\r
+        // we received a signal it is not a problem\r
       end else begin\r
         raise esocketexception.create('select returned error '+inttostr(linuxerror));\r
       end;\r
       end else begin\r
         raise esocketexception.create('select returned error '+inttostr(linuxerror));\r
       end;\r
+    end\r
+  {$ifdef select_no_autotv}\r
+    else if (result = 0) and assigned(timeout) then begin\r
+      //timeout reached: zero the timeval\r
+      timeout.tv_sec := 0;\r
+      timeout.tv_usec := 0;\r
     end;\r
     end;\r
+  end else if assigned(timeout) then begin\r
+    //successful result: subtract elapsed time\r
+    gettimemonotonic(tvend);\r
+    tv_subtract(tvend,tvstart);\r
+    tv_subtract(timeoutcopy,tvend);\r
+    timeout.tv_sec := timeoutcopy.tv_sec;\r
+    timeout.tv_usec := timeoutcopy.tv_usec;\r
+    if (timeout.tv_sec < 0) then begin\r
+      timeout.tv_sec := 0;\r
+      timeout.tv_usec := 0;\r
+    end;\r
+  {$endif} //select_no_autotv\r
   end;\r
   end;\r
+\r
   {$ifndef nosignal}\r
     sigprocmask(SIG_BLOCK,@blockset,nil);\r
   {$endif}\r
   {$ifndef nosignal}\r
     sigprocmask(SIG_BLOCK,@blockset,nil);\r
   {$endif}\r
@@ -287,7 +328,7 @@ begin
 \r
   repeat\r
 \r
 \r
   repeat\r
 \r
-    //the message loop will exit if all lasio's and ltimer's and lsignal's are destroyed\r
+    //the message loop will exit if all lasios and ltimers and lsignals are destroyed\r
     processtasks;\r
     //currenttask := nil;\r
     {beware}\r
     processtasks;\r
     //currenttask := nil;\r
     {beware}\r
@@ -308,8 +349,8 @@ begin
       selectresult := doselect(nil);\r
 \r
     end else begin\r
       selectresult := doselect(nil);\r
 \r
     end else begin\r
-      gettimeofday(tvnow);\r
-      tv_substract(tv,tvnow);\r
+      gettimemonotonic(tvnow);\r
+      tv_subtract(tv,tvnow);\r
 \r
       //writeln('timers active');\r
       if tv.tv_sec < 0 then begin\r
 \r
       //writeln('timers active');\r
       if tv.tv_sec < 0 then begin\r
@@ -333,7 +374,7 @@ end;
 procedure tselecteventcore.rmasterset(fd : integer;islistensocket : boolean);\r
 begin\r
   //writeln('rmasterset called with fd ',fd);\r
 procedure tselecteventcore.rmasterset(fd : integer;islistensocket : boolean);\r
 begin\r
   //writeln('rmasterset called with fd ',fd);\r
-  if fd > absoloutemaxs then raise esocketexception.create('file discriptor out of range');\r
+  if fd > absolutemaxs then raise esocketexception.create('file descriptor out of range');\r
   if fd > maxs then maxs := fd;\r
   if fd_isset(fd,fdsrmaster) then exit;\r
   fd_set(fd,fdsrmaster);\r
   if fd > maxs then maxs := fd;\r
   if fd_isset(fd,fdsrmaster) then exit;\r
   fd_set(fd,fdsrmaster);\r
@@ -352,7 +393,7 @@ end;
 procedure tselecteventcore.wmasterset(fd : integer);\r
 begin\r
   //writeln('wmasterset called with fd ',fd);\r
 procedure tselecteventcore.wmasterset(fd : integer);\r
 begin\r
   //writeln('wmasterset called with fd ',fd);\r
-  if fd > absoloutemaxs then raise esocketexception.create('file discriptor out of range');\r
+  if fd > absolutemaxs then raise esocketexception.create('file descriptor out of range');\r
   if fd > maxs then maxs := fd;\r
 \r
   if fd_isset(fd,fdswmaster) then exit;\r
   if fd > maxs then maxs := fd;\r
 \r
   if fd_isset(fd,fdswmaster) then exit;\r
@@ -381,7 +422,7 @@ begin
   inited := true;\r
   eventcore := tselecteventcore.create;\r
 \r
   inited := true;\r
   eventcore := tselecteventcore.create;\r
 \r
-  absoloutemaxs := absoloutemaxs_select;\r
+  absolutemaxs := absolutemaxs_select;\r
 \r
   maxs := 0;\r
   fd_zero(fdsrmaster);\r
 \r
   maxs := 0;\r
   fd_zero(fdsrmaster);\r