Hi Wolfgang.

Thank you for the extensive explanation. I was missing the basic that the thread was spawned as a single method, once the method ended, "done"... tracing the whole chain is indeed long, there is even one step more.

It took me a while to reply, because I was on holiday and was actually thinking about a solution.

Wolfgang Lux wrote:
Now turning to the +setPorts: method, it uses DO to call -registerExecutor: on 
the FileOpInfo instance on the main thread. So the code in the auxiliary thread 
now waits for the -registerExecutor: call on the main thread to finish and once 
that happens the auxiliary thread will terminate.

Next looking at the -registerExecutor: method, this uses DO again to call the 
-calculateNumFiles method on the FileExecutor instance. This call is going to 
be processed on the auxiliary thread while that thread is still waiting for the 
-registerExecutor: method to finish on the main thread. Yet, since 
-calculateNumFiles is (correctly!) declared as oneway method -registerExecutor: 
will not wait for -calculateNumFiles to terminate and just return immediately. 
So the main thread sends a reply back to the auxiliary thread which is still 
executing the -calculateNumFiles method. But once -calculateNumFiles returns, 
the DO call to -registerExecutor: on the auxiliary thread will return as well 
and hence the auxiliary thread will terminate.

So finally, we can look at -calculateNumFiles. At the end, this method calls 
-performOperation and the latter calls one of the -do... methods, e.g., 
-doMove. So if the loop in -doMove is exited, which happens once the paused 
flag is set, the -doMove method, the -performOperation method and the 
-calculateNumFiles methods all exit at once. And that means the 
-registerExecutor: can return its result and terminate the auxiliary thread.
I would see two basic ways of fixing it:
1) when "paused" the thread shouldn't quit but loop and wait for a resume, that way the status is preserved 2) The caller preserves all the necessary status and on resume re-spawns the operation thread where it previously left off.

Essentially, "FileOpInfo" calls FileOpExec, both maintain an array of files to process, the latter also having and array of processed files.

I preferred 2) and proceeded as follows:
a) I split the startOperation method in two: the user-intraction part remains in startOperation, the latter part in "detachOperationThread" b) after doCopy, if there are files left an it is not stopped in FileOpExec calls FileOpInfo's removeProcessedFile which asks FileOpExec for the processed file and removes them. It is a bit convoluted because one is an array of string,, the other of dictionaries and the passing happens through an archived NSData.... I though thread shared memory, but processedFiles was already done so. c) a subsequent "resume" after pause just calls detachOperationThread: the operation did not chance, the files to process are the remaining and a new thread gets detached without user panel.

What do you think of this?
Sadly, it only partially works: processing continues and the remaining files get copied successfully! Using "top" I see that the ancillary thread gets spawned again. However, GWorkspace remains unresponsive, one cannot click, do anything. I wonder why? GWorkspace can be now "killed" with a crl-c, there are no running processes anymore.


I also have a concern: if a user "skips" a file for some reason (e.g. during copy only older files get copied), does it result processed? I fear that it could happen that they get reprocessed.

Perhaps instead of a single remove method, a continuous syncing after each file would be safer? Why do I need a copy at all actually, can't a thread access directly the other class? It has shared memory and here DO is used only locally.

Riccardo
Index: Operation/FileOpInfo.h
===================================================================
--- Operation/FileOpInfo.h	(revision 38049)
+++ Operation/FileOpInfo.h	(working copy)
@@ -43,6 +43,8 @@
 
 - (void)sendDidChangeNotification;
 
+- (void)removeProcessedFiles;
+
 - (oneway void)endOperation;
 
 @end
@@ -84,7 +86,7 @@
   NSString *type;
   NSString *source;
   NSString *destination;
-  NSArray *files;
+  NSMutableArray *files;
   NSMutableArray *dupfiles;
   int ref;
   
Index: Operation/FileOpInfo.m
===================================================================
--- Operation/FileOpInfo.m	(revision 38049)
+++ Operation/FileOpInfo.m	(working copy)
@@ -118,7 +118,7 @@
     ASSIGN (type, tp);
     ASSIGN (source, src);
     ASSIGN (destination, dst);
-    ASSIGN (files, fls);
+    files = [[NSMutableArray arrayWithArray:fls] retain];
     
     dupfiles = [NSMutableArray new];
     
@@ -185,89 +185,114 @@
 
 - (void)startOperation
 {
-  NSPort *port[2];
-  NSArray *ports;
+  NSLog(@"startOperation");
+  if (confirm)
+    {    
+      NSString *title = nil;
+      NSString *msg = nil;
+      NSString *msg1 = nil;
+      NSString *msg2 = nil;
+      NSString *items;
 
-  if (confirm) {    
-    NSString *title = nil;
-    NSString *msg = nil;
-    NSString *msg1 = nil;
-    NSString *msg2 = nil;
-    NSString *items;
-
-    if ([files count] > 1) {
-      items = [NSString stringWithFormat: @"%lu %@", (unsigned long)[files count], NSLocalizedString(@"items", @"")];
-    } else {
-      items = NSLocalizedString(@"one item", @"");
-    }
+      if ([files count] > 1)
+        {
+          items = [NSString stringWithFormat: @"%lu %@", (unsigned long)[files count], NSLocalizedString(@"items", @"")];
+        }
+      else
+        {
+          items = NSLocalizedString(@"one item", @"");
+        }
     
-	  if ([type isEqual: NSWorkspaceMoveOperation]) {
-		  title = NSLocalizedString(@"Move", @"");
-      msg1 = [NSString stringWithFormat: @"%@ %@ %@: ", 
-                                            NSLocalizedString(@"Move", @""), 
-                                            items, 
-                                            NSLocalizedString(@"from", @"")];
-		  msg2 = NSLocalizedString(@"\nto: ", @"");
-		  msg = [NSString stringWithFormat: @"%@%@%@%@?", msg1, source, msg2, destination];
-    } else if ([type isEqual: NSWorkspaceCopyOperation]) {
-		  title = NSLocalizedString(@"Copy", @"");
-      msg1 = [NSString stringWithFormat: @"%@ %@ %@: ", 
-                                            NSLocalizedString(@"Copy", @""), 
-                                            items, 
-                                            NSLocalizedString(@"from", @"")];
-		  msg2 = NSLocalizedString(@"\nto: ", @"");
-		  msg = [NSString stringWithFormat: @"%@%@%@%@?", msg1, source, msg2, destination];
-	  } else if ([type isEqual: NSWorkspaceLinkOperation]) {
-		  title = NSLocalizedString(@"Link", @"");
-      msg1 = [NSString stringWithFormat: @"%@ %@ %@: ", 
-                                            NSLocalizedString(@"Link", @""), 
-                                            items, 
-                                            NSLocalizedString(@"from", @"")];
-		  msg2 = NSLocalizedString(@"\nto: ", @"");
-		  msg = [NSString stringWithFormat: @"%@%@%@%@?", msg1, source, msg2, destination];
-	  } else if ([type isEqual: NSWorkspaceRecycleOperation]) {
-		  title = NSLocalizedString(@"Recycler", @"");
-      msg1 = [NSString stringWithFormat: @"%@ %@ %@: ", 
-                                            NSLocalizedString(@"Move", @""), 
-                                            items, 
-                                            NSLocalizedString(@"from", @"")];
-		  msg2 = NSLocalizedString(@"\nto the Recycler", @"");
-		  msg = [NSString stringWithFormat: @"%@%@%@?", msg1, source, msg2];
-	  } else if ([type isEqual: @"GWorkspaceRecycleOutOperation"]) {
-		  title = NSLocalizedString(@"Recycler", @"");
-      msg1 = [NSString stringWithFormat: @"%@ %@ %@ ", 
-                                            NSLocalizedString(@"Move", @""), 
-                                            items, 
-                                            NSLocalizedString(@"from the Recycler", @"")];
-		  msg2 = NSLocalizedString(@"\nto: ", @"");
-		  msg = [NSString stringWithFormat: @"%@%@%@?", msg1, msg2, destination];
-	  } else if ([type isEqual: @"GWorkspaceEmptyRecyclerOperation"]) {
-		  title = NSLocalizedString(@"Recycler", @"");
-		  msg = NSLocalizedString(@"Empty the Recycler?", @"");
-	  } else if ([type isEqual: NSWorkspaceDestroyOperation]) {
-		  title = NSLocalizedString(@"Delete", @"");
-		  msg = NSLocalizedString(@"Delete the selected objects?", @"");
-	  } else if ([type isEqual: NSWorkspaceDuplicateOperation]) {
-		  title = NSLocalizedString(@"Duplicate", @"");
-		  msg = NSLocalizedString(@"Duplicate the selected objects?", @"");
-	  }
-        
-    if (NSRunAlertPanel(title, msg, 
-                        NSLocalizedString(@"OK", @""), 
-			NSLocalizedString(@"Cancel", @""), 
-                        nil) != NSAlertDefaultReturn) {
-      [self endOperation];
-      return;
+      if ([type isEqual: NSWorkspaceMoveOperation])
+        {
+          title = NSLocalizedString(@"Move", @"");
+          msg1 = [NSString stringWithFormat: @"%@ %@ %@: ", 
+                           NSLocalizedString(@"Move", @""), 
+                           items, 
+                           NSLocalizedString(@"from", @"")];
+          msg2 = NSLocalizedString(@"\nto: ", @"");
+          msg = [NSString stringWithFormat: @"%@%@%@%@?", msg1, source, msg2, destination];
+        }
+      else if ([type isEqual: NSWorkspaceCopyOperation])
+        {
+          title = NSLocalizedString(@"Copy", @"");
+          msg1 = [NSString stringWithFormat: @"%@ %@ %@: ", 
+                           NSLocalizedString(@"Copy", @""), 
+                           items, 
+                           NSLocalizedString(@"from", @"")];
+          msg2 = NSLocalizedString(@"\nto: ", @"");
+          msg = [NSString stringWithFormat: @"%@%@%@%@?", msg1, source, msg2, destination];
+        }
+      else if ([type isEqual: NSWorkspaceLinkOperation])
+        {
+          title = NSLocalizedString(@"Link", @"");
+          msg1 = [NSString stringWithFormat: @"%@ %@ %@: ", 
+                           NSLocalizedString(@"Link", @""), 
+                           items, 
+                           NSLocalizedString(@"from", @"")];
+          msg2 = NSLocalizedString(@"\nto: ", @"");
+          msg = [NSString stringWithFormat: @"%@%@%@%@?", msg1, source, msg2, destination];
+        }
+      else if ([type isEqual: NSWorkspaceRecycleOperation])
+        {
+          title = NSLocalizedString(@"Recycler", @"");
+          msg1 = [NSString stringWithFormat: @"%@ %@ %@: ", 
+                           NSLocalizedString(@"Move", @""), 
+                           items, 
+                           NSLocalizedString(@"from", @"")];
+          msg2 = NSLocalizedString(@"\nto the Recycler", @"");
+          msg = [NSString stringWithFormat: @"%@%@%@?", msg1, source, msg2];
+        }
+      else if ([type isEqual: @"GWorkspaceRecycleOutOperation"])
+        {
+          title = NSLocalizedString(@"Recycler", @"");
+          msg1 = [NSString stringWithFormat: @"%@ %@ %@ ", 
+                           NSLocalizedString(@"Move", @""), 
+                           items, 
+                           NSLocalizedString(@"from the Recycler", @"")];
+          msg2 = NSLocalizedString(@"\nto: ", @"");
+          msg = [NSString stringWithFormat: @"%@%@%@?", msg1, msg2, destination];
+        }
+      else if ([type isEqual: @"GWorkspaceEmptyRecyclerOperation"])
+        {
+          title = NSLocalizedString(@"Recycler", @"");
+          msg = NSLocalizedString(@"Empty the Recycler?", @"");
+        }
+      else if ([type isEqual: NSWorkspaceDestroyOperation])
+        {
+          title = NSLocalizedString(@"Delete", @"");
+          msg = NSLocalizedString(@"Delete the selected objects?", @"");
+        }
+      else if ([type isEqual: NSWorkspaceDuplicateOperation])
+        {
+          title = NSLocalizedString(@"Duplicate", @"");
+          msg = NSLocalizedString(@"Duplicate the selected objects?", @"");
+        }
+      
+      if (NSRunAlertPanel(title, msg, 
+                          NSLocalizedString(@"OK", @""), 
+                          NSLocalizedString(@"Cancel", @""), 
+                          nil) != NSAlertDefaultReturn) {
+        [self endOperation];
+        return;
+      }
     }
-  } 
+  [self detachOperationThread];
+}
 
+-(void)detachOperationThread
+{
+  NSPort *port[2];
+  NSArray *ports;
+
+  NSLog(@"detach operation thread");
   port[0] = (NSPort *)[NSPort port];
   port[1] = (NSPort *)[NSPort port];
-
+  
   ports = [NSArray arrayWithObjects: port[1], port[0], nil];
 
   execconn = [[NSConnection alloc] initWithReceivePort: port[0]
-				                                      sendPort: port[1]];
+                                              sendPort: port[1]];
   [execconn setRootObject: self];
   [execconn setDelegate: self];
   
@@ -281,6 +306,7 @@
       [NSThread detachNewThreadSelector: @selector(setPorts:)
 		                           toTarget: [FileOpExecutor class]
 		                         withObject: ports];
+      NSLog(@"thread detached");
     }
   NS_HANDLER
     {
@@ -317,6 +343,7 @@
 {
   if (paused == NO)
     {
+      NSLog(@"start pause remaining files: %d", [files count]);
       [pauseButt setTitle: NSLocalizedString(@"Continue", @"")];
       [stopButt setEnabled: NO];	
       paused = YES;
@@ -323,10 +350,12 @@
     }
   else
     {
+      NSLog(@"continue from pause");
+      [self detachOperationThread];
       [pauseButt setTitle: NSLocalizedString(@"Pause", @"")];
       [stopButt setEnabled: YES];	
       paused = NO;
-      [executor performOperation];
+      NSLog(@"performing operation....");
     }
 }
 
@@ -335,6 +364,44 @@
   stopped = YES;   
 }
 
+- (void)removeProcessedFiles
+{
+  NSData *pFData;
+  NSArray *pFiles;
+  NSUInteger i;
+
+
+  NSLog(@"remove processed files");
+  pFData = [executor processedFiles];
+  pFiles = [NSUnarchiver unarchiveObjectWithData: pFData];
+
+  NSLog(@"remove files: %@", pFiles);
+  for (i = 0; i < [pFiles count]; i++)
+    {
+      NSDictionary *fi;
+      NSUInteger j;
+      BOOL found;
+
+      j = 0;
+      found = NO;
+      while (j < [files count] && !found)
+        {
+          fi = [files objectAtIndex:j];
+
+          if ([[pFiles objectAtIndex:i] isEqualTo:[fi objectForKey:@"name"]])
+            found = YES;
+          else
+            i++;
+        }
+      if (found)
+        {
+          NSLog(@"found! %@", fi);
+          [files removeObjectAtIndex:j];
+        }
+    }
+  NSLog(@"removeFile - remaining files... %d", [files count]);
+}
+
 - (void)showProgressWin
 {  
   if ([win isVisible] == NO) {
@@ -652,7 +719,8 @@
   NSPort *port[2];
   NSConnection *conn;
   FileOpExecutor *executor;
-                              
+
+  NSLog(@"set ports start");
   port[0] = [thePorts objectAtIndex: 0];             
   port[1] = [thePorts objectAtIndex: 1];             
 
@@ -662,6 +730,7 @@
   executor = [[self alloc] init];
   [executor setFileop: thePorts];
   [(id)[conn rootProxy] registerExecutor: executor];
+  NSLog(@"setPorts stop");
   RELEASE (executor);
   
   RELEASE (pool);
@@ -860,7 +929,7 @@
 - (oneway void)performOperation
 {
   canupdate = YES; 
-  
+  NSLog(@"performOperation: %@", operation);  
   if ([operation isEqual: NSWorkspaceMoveOperation]
       || [operation isEqual: @"GWorkspaceRecycleOutOperation"])
     {
@@ -954,10 +1023,12 @@
 
 - (void)doCopy
 {
+  NSLog(@"start files... %d", [files count]);
   while (1)
     {
       CHECK_DONE;	
       GET_FILENAME;
+      sleep(1);
       
       if ((samename == NO) || (samename && [self removeExisting: fileinfo]))
         {
@@ -968,7 +1039,8 @@
               [procfiles addObject: filename];	
             }
         }
-      [files removeObject: fileinfo];	
+      [files removeObject: fileinfo];
+      NSLog(@"files... %d", [files count]);
       RELEASE (fileinfo); 
     }
   
@@ -975,7 +1047,12 @@
   if (([files count] == 0) || stopped)
     {
       [self done];
-    }                                          
+    }
+  else if (paused)
+    {
+      NSLog(@"paused, communicating back that we processed: %d", [procfiles count]);
+      [fileOp removeProcessedFiles];
+    }
 }
 
 - (void)doLink
_______________________________________________
Gnustep-dev mailing list
Gnustep-dev@gnu.org
https://lists.gnu.org/mailman/listinfo/gnustep-dev

Reply via email to