Back to index

lightning-sunbird  0.9+nobinonly
TestFileInput.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsIFileTransportService.h"
00039 #include "nsIStreamListener.h"
00040 #include "nsIServiceManager.h"
00041 #include "nsIComponentRegistrar.h"
00042 #include "nsIInputStream.h"
00043 #include "nsIEventQueue.h"
00044 #include "nsIEventQueueService.h"
00045 #include "prinrval.h"
00046 #include "prmon.h"
00047 #include "prcmon.h"
00048 #include "prio.h"
00049 #include "nsIFileStreams.h"
00050 #include "nsILocalFile.h"
00051 #include "nsNetUtil.h"
00052 #include "nsIPipe.h"
00053 #include "nsIOutputStream.h"
00054 #include "nsIInputStream.h"
00055 #include "nsIRunnable.h"
00056 #include "nsIThread.h"
00057 #include "nsCOMArray.h"
00058 #include "nsIChannel.h"
00059 #include "nsCOMPtr.h"
00060 #include <stdio.h>
00061 #include "nsInt64.h"
00062 
00063 static NS_DEFINE_CID(kFileTransportServiceCID, NS_FILETRANSPORTSERVICE_CID);
00064 static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
00065 
00066 
00067 #if defined(XP_MAC)
00068   #define FILE_PATH_SEPARATOR       ":"
00069 #elif defined(XP_WIN) || defined(XP_OS2)
00070   #define FILE_PATH_SEPARATOR       "\\"
00071 #elif defined(XP_UNIX) || defined(XP_BEOS)
00072   #define FILE_PATH_SEPARATOR       "/"
00073 #else
00074   #error need_to_define_your_file_path_separator_and_illegal_characters
00075 #endif
00076 
00077 PRIntervalTime gDuration = 0;
00078 PRUint32 gVolume = 0;
00079 
00080 class nsReader : public nsIRunnable, public nsIStreamListener {
00081 public:
00082     NS_DECL_ISUPPORTS
00083 
00084     NS_IMETHOD Run() {
00085         printf("waiting\n");
00086         if (!mMonitor)
00087             return NS_ERROR_OUT_OF_MEMORY;
00088         PR_EnterMonitor(mMonitor);
00089         if (mEventQueue == nsnull) 
00090             PR_CWait(this, PR_INTERVAL_NO_TIMEOUT);
00091 
00092         PR_ExitMonitor(mMonitor);
00093 
00094         printf("running\n");
00095 
00096         mEventQueue->EventLoop();
00097 
00098         printf("quitting\n");
00099         return NS_OK;
00100     }
00101 
00102     nsReader()
00103         : mEventQueue(nsnull), mStartTime(0), mThread(nsnull), mBytesRead(0)
00104     {
00105         mMonitor = PR_NewMonitor();
00106     }
00107 
00108     virtual ~nsReader() {
00109         NS_IF_RELEASE(mThread);
00110         NS_IF_RELEASE(mEventQueue);
00111         PR_DestroyMonitor(mMonitor);
00112     }
00113 
00114     nsresult Init(nsIThread* thread) {
00115         nsresult rv;
00116         mThread = thread;
00117         NS_ADDREF(mThread);
00118         PRThread* prthread;
00119         thread->GetPRThread(&prthread);
00120         PR_EnterMonitor(mMonitor);
00121         nsCOMPtr<nsIEventQueueService> eventQService =
00122                  do_GetService(kEventQueueServiceCID, &rv);
00123         if (NS_SUCCEEDED(rv)) {
00124           rv = eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, &mEventQueue);
00125         }
00126 
00127         if (NS_FAILED(rv)) return rv;
00128 
00129         // wake up event loop
00130         PR_Notify(mMonitor);
00131         PR_ExitMonitor(mMonitor);
00132 
00133         return NS_OK;
00134     }
00135 
00136     NS_IMETHOD OnStartRequest(nsIRequest *request,
00137                               nsISupports* context) {
00138         PR_EnterMonitor(mMonitor);
00139         printf("start binding\n"); 
00140         mStartTime = PR_IntervalNow();
00141         PR_ExitMonitor(mMonitor);
00142         return NS_OK;
00143     }
00144 
00145     NS_IMETHOD OnDataAvailable(nsIRequest *request, 
00146                                nsISupports* context,
00147                                nsIInputStream *aIStream, 
00148                                PRUint32 aSourceOffset,
00149                                PRUint32 aLength) {
00150         PR_EnterMonitor(mMonitor);
00151         char buf[1025];
00152         while (aLength > 0) {
00153             PRUint32 amt;
00154             /*nsresult rv = */aIStream->Read(buf, 1024, &amt);
00155             if (amt == 0) break;
00156             buf[amt] = '\0';
00157             printf(buf);
00158             aLength -= amt;
00159             mBytesRead += amt;
00160             gVolume += amt;
00161         }
00162         PR_ExitMonitor(mMonitor);
00163         return NS_OK;
00164     }
00165 
00166     NS_IMETHOD OnStopRequest(nsIRequest *request, nsISupports* context,
00167                              nsresult aStatus) {
00168         nsresult rv;
00169         PR_EnterMonitor(mMonitor);
00170         PRIntervalTime endTime = PR_IntervalNow();
00171         gDuration += (endTime - mStartTime);
00172         printf("stop binding, %d\n", aStatus);
00173         if (NS_FAILED(aStatus)) printf("channel failed.\n");
00174         printf("read %d bytes\n", mBytesRead);
00175         PR_ExitMonitor(mMonitor);
00176 
00177         // get me out of my event loop
00178         rv = mThread->Interrupt();
00179         if (NS_FAILED(rv)) return rv;
00180 
00181         return rv;
00182     }
00183 
00184 protected:
00185     nsIEventQueue*       mEventQueue;
00186     PRIntervalTime      mStartTime;
00187     nsIThread*          mThread;
00188     PRUint32            mBytesRead;
00189 
00190 private:
00191     PRMonitor*          mMonitor;
00192 };
00193 
00194 NS_IMPL_ADDREF(nsReader)
00195 NS_IMPL_RELEASE(nsReader)
00196 
00197 NS_IMETHODIMP
00198 nsReader::QueryInterface(const nsIID& aIID, void* *aInstancePtr)
00199 {
00200     if (NULL == aInstancePtr) {
00201         return NS_ERROR_NULL_POINTER; 
00202     } 
00203     if (aIID.Equals(NS_GET_IID(nsIRunnable)) ||
00204         aIID.Equals(NS_GET_IID(nsISupports))) {
00205         *aInstancePtr = NS_STATIC_CAST(nsIRunnable*, this); 
00206         NS_ADDREF_THIS(); 
00207         return NS_OK; 
00208     } 
00209     if (aIID.Equals(NS_GET_IID(nsIStreamListener))) {
00210         *aInstancePtr = NS_STATIC_CAST(nsIStreamListener*, this); 
00211         NS_ADDREF_THIS(); 
00212         return NS_OK; 
00213     } 
00214     return NS_NOINTERFACE; 
00215 }
00216 
00217 
00218 nsresult
00219 Simulated_nsFileTransport_Run(nsReader* reader, const char* path)
00220 {
00221     // duplicate the work of nsFileTransport::Run here
00222 
00223 #define NS_FILE_TRANSPORT_BUFFER_SIZE (4*1024)
00224 
00225     nsresult rv;
00226     nsCOMPtr<nsIInputStream> fileStr;
00227     nsIInputStream* bufStr = nsnull;
00228     PRUint32 sourceOffset = 0;
00229     nsCOMPtr<nsIOutputStream> out;
00230     nsCOMPtr<nsILocalFile> file;
00231 
00232     rv = reader->OnStartRequest(nsnull, nsnull);
00233     if (NS_FAILED(rv)) goto done;       // XXX should this abort the transfer?
00234 
00235     rv = NS_NewNativeLocalFile(nsDependentCString(path), PR_FALSE, getter_AddRefs(file));
00236     if (NS_FAILED(rv)) goto done;
00237 
00238     rv = NS_NewLocalFileInputStream(getter_AddRefs(fileStr), file);
00239     if (NS_FAILED(rv)) goto done;
00240 
00241     rv = NS_NewPipe(&bufStr, getter_AddRefs(out),
00242                     NS_FILE_TRANSPORT_BUFFER_SIZE,
00243                     NS_FILE_TRANSPORT_BUFFER_SIZE);
00244     if (NS_FAILED(rv)) goto done;
00245 
00246     /*
00247     if ( spec.GetFileSize() == 0) goto done;
00248     */
00249 
00250     while (PR_TRUE) {
00251         PRUint32 amt;
00252                   /* id'l change to FillFrom... */
00253         PRInt64 size;
00254         rv = file->GetFileSize(&size);
00255         if (NS_FAILED(rv)) break;
00256         rv = out->WriteFrom(fileStr, nsInt64(size), &amt);
00257         if (NS_FAILED(rv) || amt == 0) break;
00258 
00259         rv = reader->OnDataAvailable(nsnull, nsnull, bufStr, sourceOffset, amt);
00260         if (NS_FAILED(rv)) break;
00261 
00262         sourceOffset += amt;
00263     }
00264 
00265   done:
00266     NS_IF_RELEASE(bufStr);
00267 
00268     rv = reader->OnStopRequest(nsnull, nsnull, rv);
00269     return rv;
00270 }
00271 
00272 void
00273 SerialReadTest(char* dirName)
00274 {
00275     nsresult rv;
00276     PRStatus status;
00277 
00278     PRDir* dir = PR_OpenDir(dirName);
00279     NS_ASSERTION(dir, "bad dir");
00280 
00281     nsCOMArray<nsIThread> threads;
00282 
00283     PRIntervalTime startTime = PR_IntervalNow();
00284     PRDirEntry* entry;
00285 
00286     while ((entry = PR_ReadDir(dir, PR_SKIP_BOTH)) != nsnull) {
00287         char buffer[1024];
00288 
00289         sprintf(buffer, "%s%s%s" dirName, FILE_PATH_SEPARATOR, entry->name);
00290 
00291         nsReader* reader = new nsReader();
00292         NS_ASSERTION(reader, "out of memory");
00293         NS_ADDREF(reader);
00294 
00295         nsIThread* readerThread;
00296         rv = NS_NewThread(&readerThread, reader, 0, PR_JOINABLE_THREAD);
00297         NS_ASSERTION(NS_SUCCEEDED(rv), "new thread failed");
00298 
00299         rv = reader->Init(readerThread);
00300         NS_ASSERTION(NS_SUCCEEDED(rv), "init failed");
00301 
00302         // XXXbz shouldn't we put these in our array?
00303 
00304         nsIStreamListener* listener;
00305         reader->QueryInterface(NS_GET_IID(nsIStreamListener), (void**)&listener);
00306         NS_ASSERTION(listener, "QI failed");
00307 
00308         rv = Simulated_nsFileTransport_Run(reader, buffer);
00309         NS_ASSERTION(NS_SUCCEEDED(rv), "Simulated_nsFileTransport_Run failed");
00310 
00311         // the reader thread will hang on to these objects until it quits
00312         NS_RELEASE(listener);
00313         NS_RELEASE(readerThread);
00314         NS_RELEASE(reader);
00315     }
00316     PRIntervalTime endTime = PR_IntervalNow();
00317     printf("duration %d ms, volume %d\n",
00318            PR_IntervalToMilliseconds(endTime - startTime),
00319            gVolume);
00320     gVolume = 0;
00321 
00322     // now that we've forked all the async requests, wait until they're done
00323     PRUint32 threadCount = threads.Count();
00324     for (PRUint32 i = 0; i < threadCount; i++) {
00325         nsIThread* thread = threads.ObjectAt(i);
00326         thread->Join();
00327     }
00328 
00329     status = PR_CloseDir(dir);
00330     NS_ASSERTION(status == PR_SUCCESS, "can't close dir");
00331 }
00332 
00333 void
00334 ParallelReadTest(char* dirName, nsIFileTransportService* fts)
00335 {
00336     nsresult rv;
00337     PRStatus status;
00338 
00339     PRDir* dir = PR_OpenDir(dirName);
00340     NS_ASSERTION(dir, "bad dir");
00341 
00342     nsCOMArray<nsIThread> threads;
00343 
00344     PRDirEntry* entry;
00345     while ((entry = PR_ReadDir(dir, PR_SKIP_BOTH)) != nsnull) {
00346         nsCOMPtr<nsILocalFile> localFile;
00347         rv = NS_NewNativeLocalFile(nsDependentCString(dirName), PR_FALSE, getter_AddRefs(localFile));
00348         NS_ASSERTION(NS_SUCCEEDED(rv), "NS_NewNativeLocalFile failed");
00349 
00350         rv = localFile->AppendNative(nsDependentCString(entry->name));
00351         NS_ASSERTION(NS_SUCCEEDED(rv), "AppendPath failed");
00352 
00353         nsReader* reader = new nsReader();
00354         NS_ASSERTION(reader, "out of memory");
00355         NS_ADDREF(reader);
00356 
00357         nsCOMPtr<nsIThread> readerThread;
00358 
00359         rv = NS_NewThread(getter_AddRefs(readerThread), reader, 0,
00360                           PR_JOINABLE_THREAD);
00361 
00362         NS_ASSERTION(NS_SUCCEEDED(rv), "new thread failed");
00363 
00364         rv = reader->Init(readerThread);
00365         NS_ASSERTION(NS_SUCCEEDED(rv), "init failed");
00366 
00367         nsIStreamListener* listener;
00368         reader->QueryInterface(NS_GET_IID(nsIStreamListener), (void**)&listener);
00369         NS_ASSERTION(listener, "QI failed");
00370 
00371         nsITransport* trans;
00372         rv = fts->CreateTransport(localFile, PR_RDONLY, 0, PR_TRUE, &trans);
00373         NS_ASSERTION(NS_SUCCEEDED(rv), "create failed");
00374         nsCOMPtr<nsIRequest> request;
00375         rv = trans->AsyncRead(nsnull, listener, 0, -1, 0, getter_AddRefs(request));
00376         NS_ASSERTION(NS_SUCCEEDED(rv), "AsyncRead failed");
00377 
00378         // the reader thread will hang on to these objects until it quits
00379         NS_RELEASE(trans);
00380         NS_RELEASE(listener);
00381         NS_RELEASE(reader);
00382         rv = threads.AppendObject(readerThread) ? NS_OK : NS_ERROR_FAILURE;
00383         NS_ASSERTION(NS_SUCCEEDED(rv), "AppendElement failed");
00384     }
00385 
00386     // now that we've forked all the async requests, wait until they're done
00387     PRUint32 threadCount = threads.Count();
00388     for (PRUint32 i = 0; i < threadCount; i++) {
00389         nsIThread* thread = threads.ObjectAt(i);
00390         thread->Join();
00391     }
00392 
00393     status = PR_CloseDir(dir);
00394     NS_ASSERTION(status == PR_SUCCESS, "can't close dir");
00395 }
00396 
00397 int
00398 main(int argc, char* argv[])
00399 {
00400     nsresult rv;
00401 
00402     if (argc < 2) {
00403         printf("usage: %s <dir-to-read-all-files-from>\n", argv[0]);
00404         return -1;
00405     }
00406     char* dirName = argv[1];
00407 
00408     {
00409         nsCOMPtr<nsIServiceManager> servMan;
00410         NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull);
00411         nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(servMan);
00412         NS_ASSERTION(registrar, "Null nsIComponentRegistrar");
00413         if (registrar)
00414             registrar->AutoRegister(nsnull);
00415 
00416         nsCOMPtr<nsIFileTransportService> fts =
00417                  do_GetService(kFileTransportServiceCID, &rv);
00418         if (NS_FAILED(rv)) return rv;
00419 
00420         SerialReadTest(dirName);
00421 
00422         //ParallelReadTest(dirName, fts);
00423 
00424         fts->ProcessPendingRequests();
00425 
00426         printf("duration %d ms, volume %d\n",
00427                PR_IntervalToMilliseconds(gDuration),
00428                gVolume);
00429         gVolume = 0;
00430     } // this scopes the nsCOMPtrs
00431     // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM
00432     rv = NS_ShutdownXPCOM(nsnull);
00433     NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed");
00434     return 0;
00435 }
00436