Martin Paljak wrote:
On Apr 14, 2010, at 19:28 , Viktor TARASOV wrote:
Hi,

I'm testing the OpenSC pkcs11 module with Firefox.

In the logs I see the endless loop of the messages from the C_WaitForSlotEvent() and underneath calls,
non interrupted by timeout. CPU usage is considerable.

My question: should it be like this?
No. I've said before that (blocking) C_WaitForSlotEvent is broken (by me) in 
trunk.

This patch is 'working for me'.
It was applied to the IAS/ECC branch and tested in WinXP SP3.

If no objections, I'll apply it to the trunk.

Kind wishes,
Viktor.

--
Viktor Tarasov  <viktor.tara...@opentrust.com>

Index: opensc.trunk/src/tools/util.c
===================================================================
--- opensc.trunk/src/tools/util.c	(révision 4343)
+++ opensc.trunk/src/tools/util.c	(copie de travail)
@@ -23,7 +23,7 @@
 
 		if (sc_ctx_get_reader_count(ctx) == 0) {
 			fprintf(stderr, "Waiting for a reader to be attached...\n");
-			r = sc_wait_for_event(ctx, SC_EVENT_READER_ATTACHED, &found, &event, -1);
+			r = sc_wait_for_event(ctx, SC_EVENT_READER_ATTACHED, &found, &event, -1, NULL);
 			if (r < 0) {
 				fprintf(stderr, "Error while waiting for a reader: %s\n", sc_strerror(r));
 				return 3;
@@ -35,7 +35,7 @@
 			}
 		}
 		fprintf(stderr, "Waiting for a card to be inserted...\n");
-		r = sc_wait_for_event(ctx, SC_EVENT_CARD_INSERTED, &found, &event, -1);
+		r = sc_wait_for_event(ctx, SC_EVENT_CARD_INSERTED, &found, &event, -1, NULL);
 		if (r < 0) {
 			fprintf(stderr, "Error while waiting for a card: %s\n", sc_strerror(r));
 			return 3;
Index: opensc.trunk/src/pkcs11/pkcs11-global.c
===================================================================
--- opensc.trunk/src/pkcs11/pkcs11-global.c	(révision 4343)
+++ opensc.trunk/src/pkcs11/pkcs11-global.c	(copie de travail)
@@ -608,13 +608,14 @@
 			 CK_VOID_PTR pReserved) /* reserved.  Should be NULL_PTR */
 {
 	sc_reader_t *found;
-	int r;
 	unsigned int mask, events;
+	void *reader_states = NULL;
+	CK_SLOT_ID slot_id;
 	CK_RV rv;
+	int ii, r;
 	
-	if (pReserved != NULL_PTR) {
+	if (pReserved != NULL_PTR)
 		return  CKR_ARGUMENTS_BAD;
-	}
 
 	sc_debug(context, SC_LOG_DEBUG_NORMAL, "C_WaitForSlotEvent(block=%d)", !(flags & CKF_DONT_BLOCK));
 #if 0
@@ -633,21 +634,25 @@
 		mask |= SC_EVENT_READER_EVENTS;
 	}
 
-	if ((rv = slot_find_changed(pSlot, mask)) == CKR_OK
-	 || (flags & CKF_DONT_BLOCK))
+	rv = slot_find_changed(&slot_id, mask);
+	if ((rv == CKR_OK) || (flags & CKF_DONT_BLOCK))
 		goto out;
 
 again:
+	sc_debug(context, SC_LOG_DEBUG_NORMAL, "C_WaitForSlotEvent() reader_states:%p", reader_states);
 	sc_pkcs11_unlock();
-	r = sc_wait_for_event(context, mask, &found, &events, -1);
-
+	r = sc_wait_for_event(context, mask, &found, &events, -1, &reader_states);
 	if (sc_pkcs11_conf.plug_and_play && events & SC_EVENT_READER_ATTACHED) {
 		/* NSS/Firefox Triggers a C_GetSlotList(NULL) only if a slot ID is returned that it does not know yet
 		   Change the first hotplug slot id on every call to make this happen.
 		*/
 		sc_pkcs11_slot_t *hotplug_slot = list_get_at(&virtual_slots, 0);
 		*pSlot= hotplug_slot->id -1;
-		rv = CKR_OK;
+	
+		rv = sc_pkcs11_lock();
+		if (rv != CKR_OK)
+			return rv;
+
 		goto out;
 	}
 	/* Was C_Finalize called ? */
@@ -665,10 +670,21 @@
 
 	/* If no changed slot was found (maybe an unsupported card
 	 * was inserted/removed) then go waiting again */
-	if ((rv = slot_find_changed(pSlot, mask)) != CKR_OK)
+	rv = slot_find_changed(&slot_id, mask);
+	if (rv != CKR_OK)
 		goto again;
 
-out:	sc_debug(context, SC_LOG_DEBUG_NORMAL, "C_WaitForSlotEvent() = %s, event in 0x%lx", lookup_enum (RV_T, rv), *pSlot);
+out:	
+	if (pSlot)
+		*pSlot = slot_id;
+
+	/* Free allocated readers states holder */
+	if (reader_states)   {
+		sc_debug(context, SC_LOG_DEBUG_NORMAL, "free reader states");
+		sc_wait_for_event(context, 0, NULL, NULL, -1, &reader_states);
+	}
+
+	sc_debug(context, SC_LOG_DEBUG_NORMAL, "C_WaitForSlotEvent() = %s, event in 0x%lx", lookup_enum (RV_T, rv), *pSlot);
 	sc_pkcs11_unlock();
 	return rv;
 }
Index: opensc.trunk/src/libopensc/reader-pcsc.c
===================================================================
--- opensc.trunk/src/libopensc/reader-pcsc.c	(révision 4343)
+++ opensc.trunk/src/libopensc/reader-pcsc.c	(copie de travail)
@@ -953,11 +953,9 @@
 
 /* Wait for an event to occur.
  */
-static int pcsc_wait_for_event(sc_context_t *ctx,
-			       void *reader_data,
-                               unsigned int event_mask,
-                               sc_reader_t **event_reader,
-			       unsigned int *event, int timeout)
+static int pcsc_wait_for_event(sc_context_t *ctx, void *reader_data,
+                               unsigned int event_mask, sc_reader_t **event_reader, unsigned int *event, 
+			       int timeout, void **reader_states)
 {
 	struct pcsc_global_private_data *gpriv = (struct pcsc_global_private_data *)reader_data;
 	LONG rv;
@@ -968,26 +966,40 @@
 
 	SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL);
 
-	rgReaderStates = (SCARD_READERSTATE_A *) calloc(sc_ctx_get_reader_count(ctx) + 1, sizeof(SCARD_READERSTATE_A));
-	if (!rgReaderStates)
-		return SC_ERROR_OUT_OF_MEMORY;
+	if (!event_reader && !event && reader_states)   {
+		sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "free allocated reader states");
+		free(*reader_states);
+		*reader_states = NULL;
+		SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS);
+	}
 
-	/* Find out the current status */
-	num_watch = sc_ctx_get_reader_count(ctx);
-	sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Trying to watch %d readers", num_watch);
-	for (i = 0; i < num_watch; i++) {
-		rgReaderStates[i].szReader = sc_ctx_get_reader(ctx, i)->name;
-		rgReaderStates[i].dwCurrentState = SCARD_STATE_UNAWARE;
-		rgReaderStates[i].dwEventState = SCARD_STATE_UNAWARE;
-	}
+	if (reader_states == NULL || *reader_states == NULL) {
+		rgReaderStates = (SCARD_READERSTATE_A *) calloc(sc_ctx_get_reader_count(ctx) + 2, sizeof(SCARD_READERSTATE_A));
+		if (!rgReaderStates)
+			SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY);
+
+		/* Find out the current status */
+		num_watch = sc_ctx_get_reader_count(ctx);
+		sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Trying to watch %d readers", num_watch);
+		for (i = 0; i < num_watch; i++) {
+			rgReaderStates[i].szReader = sc_ctx_get_reader(ctx, i)->name;
+			rgReaderStates[i].dwCurrentState = SCARD_STATE_UNAWARE;
+			rgReaderStates[i].dwEventState = SCARD_STATE_UNAWARE;
+		}
 #ifndef __APPLE__ /* OS X 10.6.2 does not support PnP notification */
-	if (event_mask & SC_EVENT_READER_ATTACHED) {
-		rgReaderStates[i].szReader = "\\\\?PnP?\\Notification";
-		rgReaderStates[i].dwCurrentState = SCARD_STATE_UNAWARE;
-		rgReaderStates[i].dwEventState = SCARD_STATE_UNAWARE;
-		num_watch++;
+		if (event_mask & SC_EVENT_READER_ATTACHED) {
+			rgReaderStates[i].szReader = "\\\\?PnP?\\Notification";
+			rgReaderStates[i].dwCurrentState = SCARD_STATE_UNAWARE;
+			rgReaderStates[i].dwEventState = SCARD_STATE_UNAWARE;
+			num_watch++;
+		}
+#endif
 	}
-#endif
+	else {
+		rgReaderStates = (SCARD_READERSTATE_A *)(*reader_states);
+		for (num_watch = 0; rgReaderStates[num_watch].szReader; num_watch++)
+			sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "re-use reader '%s'", rgReaderStates[num_watch].szReader);
+	}
 #ifndef _WIN32
 	/* Establish a new context, assuming that it is called from a different thread with pcsc-lite */
 	if (gpriv->pcsc_wait_ctx == -1) {
@@ -1028,9 +1040,11 @@
 		*event = 0;
 		for (i = 0, rsp = rgReaderStates; i < num_watch; i++, rsp++) {
 			unsigned long state, prev_state;
-			sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "%s before=0x%04X now=0x%04X", rsp->szReader, rsp->dwCurrentState, rsp->dwEventState);
+			sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "'%s' before=0x%04X now=0x%04X", rsp->szReader, 
+					rsp->dwCurrentState, rsp->dwEventState);
 			prev_state = rsp->dwCurrentState;
 			state = rsp->dwEventState;
+			rsp->dwCurrentState = rsp->dwEventState;
 			if (state & SCARD_STATE_CHANGED) {
 
 				/* check for hotplug events  */
@@ -1065,14 +1079,13 @@
 					*event_reader = sc_ctx_get_reader_by_name(ctx, rsp->szReader);
 					r = SC_SUCCESS;
 					goto out;
-					SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS);
 				}
 				
 			}
 
 			/* No match - copy the state so pcscd knows
 			 * what to watch out for */
-			rsp->dwCurrentState = rsp->dwEventState;
+			//rsp->dwCurrentState = rsp->dwEventState;
 		}
 
 		if (timeout == 0) {
@@ -1085,7 +1098,6 @@
 			timeout = INFINITE;
 		}
 
-		sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Sleeping call, timeout 0x%lx", timeout);
 		rv = gpriv->SCardGetStatusChange(gpriv->pcsc_wait_ctx, timeout, rgReaderStates, num_watch);
 
 		if (rv == (LONG) SCARD_E_CANCELLED) {
@@ -1106,7 +1118,14 @@
 		}
 	}
 out:
-	free(rgReaderStates);
+	if (!reader_states)   {
+		free(rgReaderStates);
+	}
+	else if (*reader_states == NULL)   {
+		sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "return allocated 'reader states'");
+		*reader_states = rgReaderStates;
+	}
+
 	SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, r);
 }
 
Index: opensc.trunk/src/libopensc/ctx.c
===================================================================
--- opensc.trunk/src/libopensc/ctx.c	(révision 4343)
+++ opensc.trunk/src/libopensc/ctx.c	(copie de travail)
@@ -781,16 +781,18 @@
 }
 
 
-int sc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, sc_reader_t **event_reader, unsigned int *event, int timeout)
+int sc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, sc_reader_t **event_reader, unsigned int *event, int timeout,
+		void **reader_states)
 {
         int i;
         const struct sc_reader_driver *driver;
         SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL);
         for (i = 0; ctx->reader_drivers[i] != NULL; i++) {
-                sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "trying %s", ctx->reader_drivers[i]->short_name);
+                sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "trying to wait event from %s", ctx->reader_drivers[i]->short_name);
                 driver = ctx->reader_drivers[i];
                 if (driver->ops->wait_for_event != NULL)                                        		
-		        return driver->ops->wait_for_event(ctx, ctx->reader_drv_data[i], event_mask, event_reader, event, timeout);
+		        return driver->ops->wait_for_event(ctx, ctx->reader_drv_data[i], event_mask, event_reader, event, timeout,
+					reader_states);
         }
         return SC_ERROR_NOT_SUPPORTED;
 }
Index: opensc.trunk/src/libopensc/opensc.h
===================================================================
--- opensc.trunk/src/libopensc/opensc.h	(révision 4343)
+++ opensc.trunk/src/libopensc/opensc.h	(copie de travail)
@@ -396,7 +396,9 @@
 	int (*perform_verify)(struct sc_reader *, struct sc_pin_cmd_data *);
 
 	/* Wait for an event */
-	int (*wait_for_event)(struct sc_context *ctx, void *priv_data, unsigned int event_mask, sc_reader_t **event_reader, unsigned int *event, int timeout);
+	int (*wait_for_event)(struct sc_context *ctx, void *priv_data, 
+			unsigned int event_mask, sc_reader_t **event_reader, unsigned int *event, 
+			int timeout, void **reader_states);
 	/* Reset a reader */
 	int (*reset)(struct sc_reader *);
 };
@@ -819,7 +821,8 @@
  * @retval = 1 if the timeout occured
  */
 int sc_wait_for_event(sc_context_t *ctx, unsigned int event_mask,
-                      sc_reader_t **event_reader, unsigned int *event, int timeout);
+                      sc_reader_t **event_reader, unsigned int *event, 
+		      int timeout, void **reader_states);
 
 /**
  * Resets the card.
_______________________________________________
opensc-devel mailing list
opensc-devel@lists.opensc-project.org
http://www.opensc-project.org/mailman/listinfo/opensc-devel

Reply via email to