grpc 1.0.0.pre1 → 1.0.0.pre2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of grpc might be problematic. Click here for more details.

Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +1 -37
  3. data/include/grpc/impl/codegen/compression_types.h +16 -1
  4. data/include/grpc/impl/codegen/grpc_types.h +23 -15
  5. data/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c +4 -2
  6. data/src/core/ext/transport/chttp2/transport/chttp2_plugin.c +3 -0
  7. data/src/core/ext/transport/chttp2/transport/chttp2_transport.c +305 -64
  8. data/src/core/ext/transport/chttp2/transport/internal.h +46 -19
  9. data/src/core/ext/transport/chttp2/transport/parsing.c +6 -5
  10. data/src/core/ext/transport/chttp2/transport/stream_lists.c +11 -9
  11. data/src/core/ext/transport/chttp2/transport/writing.c +13 -3
  12. data/src/core/lib/iomgr/endpoint.c +4 -0
  13. data/src/core/lib/iomgr/endpoint.h +4 -0
  14. data/src/core/lib/iomgr/ev_epoll_linux.c +161 -116
  15. data/src/core/lib/iomgr/ev_poll_and_epoll_posix.c +3 -0
  16. data/src/core/lib/iomgr/ev_poll_posix.c +3 -0
  17. data/src/core/lib/iomgr/ev_posix.c +4 -0
  18. data/src/core/lib/iomgr/ev_posix.h +4 -0
  19. data/src/core/lib/iomgr/exec_ctx.c +7 -3
  20. data/src/core/lib/iomgr/exec_ctx.h +5 -1
  21. data/src/core/lib/iomgr/iomgr.c +3 -0
  22. data/src/core/lib/iomgr/network_status_tracker.c +9 -6
  23. data/src/core/lib/iomgr/network_status_tracker.h +4 -0
  24. data/src/core/lib/iomgr/tcp_posix.c +14 -4
  25. data/src/core/lib/iomgr/tcp_server_posix.c +2 -1
  26. data/src/core/lib/iomgr/tcp_windows.c +10 -3
  27. data/src/core/lib/iomgr/workqueue.h +25 -14
  28. data/src/core/lib/iomgr/workqueue_posix.c +1 -7
  29. data/src/core/lib/iomgr/workqueue_posix.h +5 -0
  30. data/src/core/lib/iomgr/workqueue_windows.c +22 -0
  31. data/src/core/lib/security/transport/secure_endpoint.c +13 -5
  32. data/src/core/lib/support/log.c +10 -9
  33. data/src/core/lib/surface/server.c +45 -31
  34. data/src/core/lib/surface/version.c +1 -1
  35. data/src/core/lib/transport/connectivity_state.c +3 -0
  36. data/src/ruby/bin/math_client.rb +1 -1
  37. data/src/ruby/bin/{math.rb → math_pb.rb} +0 -0
  38. data/src/ruby/bin/math_server.rb +1 -1
  39. data/src/ruby/bin/{math_services.rb → math_services_pb.rb} +4 -4
  40. data/src/ruby/lib/grpc/version.rb +1 -1
  41. data/src/ruby/pb/grpc/health/checker.rb +1 -1
  42. data/src/ruby/pb/grpc/health/v1/{health.rb → health_pb.rb} +0 -0
  43. data/src/ruby/pb/grpc/health/v1/{health_services.rb → health_services_pb.rb} +1 -1
  44. data/src/ruby/pb/grpc/testing/duplicate/{echo_duplicate_services.rb → echo_duplicate_services_pb.rb} +2 -2
  45. data/src/ruby/pb/grpc/testing/{metrics.rb → metrics_pb.rb} +1 -1
  46. data/src/ruby/pb/grpc/testing/{metrics_services.rb → metrics_services_pb.rb} +2 -2
  47. data/src/ruby/pb/src/proto/grpc/testing/{empty.rb → empty_pb.rb} +0 -0
  48. data/src/ruby/pb/src/proto/grpc/testing/{messages.rb → messages_pb.rb} +8 -10
  49. data/src/ruby/pb/src/proto/grpc/testing/{test.rb → test_pb.rb} +2 -2
  50. data/src/ruby/pb/src/proto/grpc/testing/{test_services.rb → test_services_pb.rb} +1 -1
  51. data/src/ruby/pb/test/client.rb +3 -3
  52. data/src/ruby/pb/test/server.rb +3 -3
  53. data/src/ruby/spec/pb/duplicate/codegen_spec.rb +2 -2
  54. data/src/ruby/spec/pb/health/checker_spec.rb +4 -4
  55. metadata +15 -19
  56. data/src/ruby/pb/test/proto/empty.rb +0 -15
  57. data/src/ruby/pb/test/proto/messages.rb +0 -80
  58. data/src/ruby/pb/test/proto/test.rb +0 -14
  59. data/src/ruby/pb/test/proto/test_services.rb +0 -64
@@ -305,6 +305,22 @@ typedef struct grpc_chttp2_executor_action_header {
305
305
  void *arg;
306
306
  } grpc_chttp2_executor_action_header;
307
307
 
308
+ typedef enum {
309
+ /** no writing activity */
310
+ GRPC_CHTTP2_WRITING_INACTIVE,
311
+ /** write has been requested, but not scheduled yet */
312
+ GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER,
313
+ GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER,
314
+ /** write has been requested and scheduled against the workqueue */
315
+ GRPC_CHTTP2_WRITE_SCHEDULED,
316
+ /** write has been initiated after being reaped from the workqueue */
317
+ GRPC_CHTTP2_WRITING,
318
+ /** write has been initiated, AND another write needs to be started once it's
319
+ done */
320
+ GRPC_CHTTP2_WRITING_STALE_WITH_POLLER,
321
+ GRPC_CHTTP2_WRITING_STALE_NO_POLLER,
322
+ } grpc_chttp2_write_state;
323
+
308
324
  struct grpc_chttp2_transport {
309
325
  grpc_transport base; /* must be first */
310
326
  gpr_refcount refs;
@@ -319,10 +335,10 @@ struct grpc_chttp2_transport {
319
335
 
320
336
  /** is a thread currently in the global lock */
321
337
  bool global_active;
322
- /** is a thread currently writing */
323
- bool writing_active;
324
338
  /** is a thread currently parsing */
325
339
  bool parsing_active;
340
+ /** write execution state of the transport */
341
+ grpc_chttp2_write_state write_state;
326
342
 
327
343
  grpc_chttp2_executor_action_header *pending_actions_head;
328
344
  grpc_chttp2_executor_action_header *pending_actions_tail;
@@ -342,7 +358,8 @@ struct grpc_chttp2_transport {
342
358
  /** global state for reading/writing */
343
359
  grpc_chttp2_transport_global global;
344
360
  /** state only accessible by the chain of execution that
345
- set writing_active=1 */
361
+ set writing_state >= GRPC_WRITING, and only by the writing closure
362
+ chain. */
346
363
  grpc_chttp2_transport_writing writing;
347
364
  /** state only accessible by the chain of execution that
348
365
  set parsing_active=1 */
@@ -363,6 +380,8 @@ struct grpc_chttp2_transport {
363
380
  grpc_closure reading_action;
364
381
  /** closure to actually do parsing */
365
382
  grpc_closure parsing_action;
383
+ /** closure to initiate writing */
384
+ grpc_closure initiate_writing;
366
385
 
367
386
  /** incoming read bytes */
368
387
  gpr_slice_buffer read_buffer;
@@ -436,8 +455,10 @@ typedef struct {
436
455
  bool seen_error;
437
456
  bool exceeded_metadata_size;
438
457
 
439
- /** the error that resulted in this stream being removed */
440
- grpc_error *removal_error;
458
+ /** the error that resulted in this stream being read-closed */
459
+ grpc_error *read_closed_error;
460
+ /** the error that resulted in this stream being write-closed */
461
+ grpc_error *write_closed_error;
441
462
 
442
463
  bool published_initial_metadata;
443
464
  bool published_trailing_metadata;
@@ -514,15 +535,20 @@ struct grpc_chttp2_stream {
514
535
  };
515
536
 
516
537
  /** Transport writing call flow:
517
- chttp2_transport.c calls grpc_chttp2_unlocking_check_writes to see if writes
518
- are required;
519
- if they are, chttp2_transport.c calls grpc_chttp2_perform_writes to do the
520
- writes.
521
- Once writes have been completed (meaning another write could potentially be
522
- started),
523
- grpc_chttp2_terminate_writing is called. This will call
524
- grpc_chttp2_cleanup_writing, at which
525
- point the write phase is complete. */
538
+ grpc_chttp2_initiate_write() is called anywhere that we know bytes need to
539
+ go out on the wire.
540
+ If no other write has been started, a task is enqueued onto our workqueue.
541
+ When that task executes, it obtains the global lock, and gathers the data
542
+ to write.
543
+ The global lock is dropped and we do the syscall to write.
544
+ After writing, a follow-up check is made to see if another round of writing
545
+ should be performed.
546
+
547
+ The actual call chain is documented in the implementation of this function.
548
+ */
549
+ void grpc_chttp2_initiate_write(grpc_exec_ctx *exec_ctx,
550
+ grpc_chttp2_transport_global *transport_global,
551
+ bool covered_by_poller, const char *reason);
526
552
 
527
553
  /** Someone is unlocking the transport mutex: check to see if writes
528
554
  are required, and schedule them if so */
@@ -610,9 +636,8 @@ int grpc_chttp2_list_pop_check_read_ops(
610
636
  void grpc_chttp2_list_add_writing_stalled_by_transport(
611
637
  grpc_chttp2_transport_writing *transport_writing,
612
638
  grpc_chttp2_stream_writing *stream_writing);
613
- void grpc_chttp2_list_flush_writing_stalled_by_transport(
614
- grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing,
615
- bool is_window_available);
639
+ bool grpc_chttp2_list_flush_writing_stalled_by_transport(
640
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing);
616
641
 
617
642
  void grpc_chttp2_list_add_stalled_by_transport(
618
643
  grpc_chttp2_transport_writing *transport_writing,
@@ -822,7 +847,9 @@ void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx,
822
847
 
823
848
  /** add a ref to the stream and add it to the writable list;
824
849
  ref will be dropped in writing.c */
825
- void grpc_chttp2_become_writable(grpc_chttp2_transport_global *transport_global,
826
- grpc_chttp2_stream_global *stream_global);
850
+ void grpc_chttp2_become_writable(grpc_exec_ctx *exec_ctx,
851
+ grpc_chttp2_transport_global *transport_global,
852
+ grpc_chttp2_stream_global *stream_global,
853
+ bool covered_by_poller, const char *reason);
827
854
 
828
855
  #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INTERNAL_H */
@@ -154,10 +154,8 @@ void grpc_chttp2_publish_reads(
154
154
  transport_parsing, outgoing_window);
155
155
  is_zero = transport_global->outgoing_window <= 0;
156
156
  if (was_zero && !is_zero) {
157
- while (grpc_chttp2_list_pop_stalled_by_transport(transport_global,
158
- &stream_global)) {
159
- grpc_chttp2_become_writable(transport_global, stream_global);
160
- }
157
+ grpc_chttp2_initiate_write(exec_ctx, transport_global, false,
158
+ "new_global_flow_control");
161
159
  }
162
160
 
163
161
  if (transport_parsing->incoming_window <
@@ -168,6 +166,8 @@ void grpc_chttp2_publish_reads(
168
166
  announce_incoming_window, announce_bytes);
169
167
  GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", transport_parsing,
170
168
  incoming_window, announce_bytes);
169
+ grpc_chttp2_initiate_write(exec_ctx, transport_global, false,
170
+ "global incoming window");
171
171
  }
172
172
 
173
173
  /* for each stream that saw an update, fixup global state */
@@ -190,7 +190,8 @@ void grpc_chttp2_publish_reads(
190
190
  outgoing_window);
191
191
  is_zero = stream_global->outgoing_window <= 0;
192
192
  if (was_zero && !is_zero) {
193
- grpc_chttp2_become_writable(transport_global, stream_global);
193
+ grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global,
194
+ false, "stream.read_flow_control");
194
195
  }
195
196
 
196
197
  stream_global->max_recv_bytes -= (uint32_t)GPR_MIN(
@@ -329,6 +329,7 @@ void grpc_chttp2_list_add_writing_stalled_by_transport(
329
329
  grpc_chttp2_transport_writing *transport_writing,
330
330
  grpc_chttp2_stream_writing *stream_writing) {
331
331
  grpc_chttp2_stream *stream = STREAM_FROM_WRITING(stream_writing);
332
+ gpr_log(GPR_DEBUG, "writing stalled %d", stream->global.id);
332
333
  if (!stream->included[GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT]) {
333
334
  GRPC_CHTTP2_STREAM_REF(&stream->global, "chttp2_writing_stalled");
334
335
  }
@@ -336,27 +337,28 @@ void grpc_chttp2_list_add_writing_stalled_by_transport(
336
337
  GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT);
337
338
  }
338
339
 
339
- void grpc_chttp2_list_flush_writing_stalled_by_transport(
340
- grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing,
341
- bool is_window_available) {
340
+ bool grpc_chttp2_list_flush_writing_stalled_by_transport(
341
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing) {
342
342
  grpc_chttp2_stream *stream;
343
+ bool out = false;
343
344
  grpc_chttp2_transport *transport = TRANSPORT_FROM_WRITING(transport_writing);
344
345
  while (stream_list_pop(transport, &stream,
345
346
  GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT)) {
346
- if (is_window_available) {
347
- grpc_chttp2_become_writable(&transport->global, &stream->global);
348
- } else {
349
- grpc_chttp2_list_add_stalled_by_transport(transport_writing,
350
- &stream->writing);
351
- }
347
+ gpr_log(GPR_DEBUG, "move %d from writing stalled to just stalled",
348
+ stream->global.id);
349
+ grpc_chttp2_list_add_stalled_by_transport(transport_writing,
350
+ &stream->writing);
352
351
  GRPC_CHTTP2_STREAM_UNREF(exec_ctx, &stream->global,
353
352
  "chttp2_writing_stalled");
353
+ out = true;
354
354
  }
355
+ return out;
355
356
  }
356
357
 
357
358
  void grpc_chttp2_list_add_stalled_by_transport(
358
359
  grpc_chttp2_transport_writing *transport_writing,
359
360
  grpc_chttp2_stream_writing *stream_writing) {
361
+ gpr_log(GPR_DEBUG, "stalled %d", stream_writing->id);
360
362
  stream_list_add(TRANSPORT_FROM_WRITING(transport_writing),
361
363
  STREAM_FROM_WRITING(stream_writing),
362
364
  GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT);
@@ -75,9 +75,13 @@ int grpc_chttp2_unlocking_check_writes(
75
75
 
76
76
  GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("write", transport_writing, outgoing_window,
77
77
  transport_global, outgoing_window);
78
- bool is_window_available = transport_writing->outgoing_window > 0;
79
- grpc_chttp2_list_flush_writing_stalled_by_transport(
80
- exec_ctx, transport_writing, is_window_available);
78
+ if (transport_writing->outgoing_window > 0) {
79
+ while (grpc_chttp2_list_pop_stalled_by_transport(transport_global,
80
+ &stream_global)) {
81
+ grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global,
82
+ false, "transport.read_flow_control");
83
+ }
84
+ }
81
85
 
82
86
  /* for each grpc_chttp2_stream that's become writable, frame it's data
83
87
  (according to available window sizes) and add to the output buffer */
@@ -331,6 +335,12 @@ void grpc_chttp2_cleanup_writing(
331
335
  grpc_chttp2_stream_writing *stream_writing;
332
336
  grpc_chttp2_stream_global *stream_global;
333
337
 
338
+ if (grpc_chttp2_list_flush_writing_stalled_by_transport(exec_ctx,
339
+ transport_writing)) {
340
+ grpc_chttp2_initiate_write(exec_ctx, transport_global, false,
341
+ "resume_stalled_stream");
342
+ }
343
+
334
344
  while (grpc_chttp2_list_pop_written_stream(
335
345
  transport_global, transport_writing, &stream_global, &stream_writing)) {
336
346
  if (stream_writing->sent_initial_metadata) {
@@ -65,3 +65,7 @@ void grpc_endpoint_destroy(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep) {
65
65
  char* grpc_endpoint_get_peer(grpc_endpoint* ep) {
66
66
  return ep->vtable->get_peer(ep);
67
67
  }
68
+
69
+ grpc_workqueue* grpc_endpoint_get_workqueue(grpc_endpoint* ep) {
70
+ return ep->vtable->get_workqueue(ep);
71
+ }
@@ -51,6 +51,7 @@ struct grpc_endpoint_vtable {
51
51
  gpr_slice_buffer *slices, grpc_closure *cb);
52
52
  void (*write)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
53
53
  gpr_slice_buffer *slices, grpc_closure *cb);
54
+ grpc_workqueue *(*get_workqueue)(grpc_endpoint *ep);
54
55
  void (*add_to_pollset)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
55
56
  grpc_pollset *pollset);
56
57
  void (*add_to_pollset_set)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
@@ -69,6 +70,9 @@ void grpc_endpoint_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
69
70
 
70
71
  char *grpc_endpoint_get_peer(grpc_endpoint *ep);
71
72
 
73
+ /* Retrieve a reference to the workqueue associated with this endpoint */
74
+ grpc_workqueue *grpc_endpoint_get_workqueue(grpc_endpoint *ep);
75
+
72
76
  /* Write slices out to the socket.
73
77
 
74
78
  If the connection is ready for more data after the end of the call, it
@@ -57,6 +57,7 @@
57
57
  #include "src/core/lib/iomgr/ev_posix.h"
58
58
  #include "src/core/lib/iomgr/iomgr_internal.h"
59
59
  #include "src/core/lib/iomgr/wakeup_fd_posix.h"
60
+ #include "src/core/lib/iomgr/workqueue.h"
60
61
  #include "src/core/lib/profiling/timers.h"
61
62
  #include "src/core/lib/support/block_annotate.h"
62
63
 
@@ -113,9 +114,7 @@ struct grpc_fd {
113
114
  grpc_closure *read_closure;
114
115
  grpc_closure *write_closure;
115
116
 
116
- /* The polling island to which this fd belongs to and the mutex protecting the
117
- the field */
118
- gpr_mu pi_mu;
117
+ /* The polling island to which this fd belongs to (protected by mu) */
119
118
  struct polling_island *polling_island;
120
119
 
121
120
  struct grpc_fd *freelist_next;
@@ -152,16 +151,17 @@ static void fd_global_shutdown(void);
152
151
  * Polling island Declarations
153
152
  */
154
153
 
155
- // #define GRPC_PI_REF_COUNT_DEBUG
154
+ //#define GRPC_PI_REF_COUNT_DEBUG
156
155
  #ifdef GRPC_PI_REF_COUNT_DEBUG
157
156
 
158
157
  #define PI_ADD_REF(p, r) pi_add_ref_dbg((p), (r), __FILE__, __LINE__)
159
- #define PI_UNREF(p, r) pi_unref_dbg((p), (r), __FILE__, __LINE__)
158
+ #define PI_UNREF(exec_ctx, p, r) \
159
+ pi_unref_dbg((exec_ctx), (p), (r), __FILE__, __LINE__)
160
160
 
161
161
  #else /* defined(GRPC_PI_REF_COUNT_DEBUG) */
162
162
 
163
163
  #define PI_ADD_REF(p, r) pi_add_ref((p))
164
- #define PI_UNREF(p, r) pi_unref((p))
164
+ #define PI_UNREF(exec_ctx, p, r) pi_unref((exec_ctx), (p))
165
165
 
166
166
  #endif /* !defined(GPRC_PI_REF_COUNT_DEBUG) */
167
167
 
@@ -172,7 +172,7 @@ typedef struct polling_island {
172
172
  Once the ref count becomes zero, this structure is destroyed which means
173
173
  we should ensure that there is never a scenario where a PI_ADD_REF() is
174
174
  racing with a PI_UNREF() that just made the ref_count zero. */
175
- gpr_refcount ref_count;
175
+ gpr_atm ref_count;
176
176
 
177
177
  /* Pointer to the polling_island this merged into.
178
178
  * merged_to value is only set once in polling_island's lifetime (and that too
@@ -184,6 +184,9 @@ typedef struct polling_island {
184
184
  * (except mu and ref_count) are invalid and must be ignored. */
185
185
  gpr_atm merged_to;
186
186
 
187
+ /* The workqueue associated with this polling island */
188
+ grpc_workqueue *workqueue;
189
+
187
190
  /* The fd of the underlying epoll set */
188
191
  int epoll_fd;
189
192
 
@@ -191,11 +194,6 @@ typedef struct polling_island {
191
194
  size_t fd_cnt;
192
195
  size_t fd_capacity;
193
196
  grpc_fd **fds;
194
-
195
- /* Polling islands that are no longer needed are kept in a freelist so that
196
- they can be reused. This field points to the next polling island in the
197
- free list */
198
- struct polling_island *next_free;
199
197
  } polling_island;
200
198
 
201
199
  /*******************************************************************************
@@ -253,13 +251,14 @@ struct grpc_pollset_set {
253
251
  * Common helpers
254
252
  */
255
253
 
256
- static void append_error(grpc_error **composite, grpc_error *error,
254
+ static bool append_error(grpc_error **composite, grpc_error *error,
257
255
  const char *desc) {
258
- if (error == GRPC_ERROR_NONE) return;
256
+ if (error == GRPC_ERROR_NONE) return true;
259
257
  if (*composite == GRPC_ERROR_NONE) {
260
258
  *composite = GRPC_ERROR_CREATE(desc);
261
259
  }
262
260
  *composite = grpc_error_add_child(*composite, error);
261
+ return false;
263
262
  }
264
263
 
265
264
  /*******************************************************************************
@@ -275,11 +274,8 @@ static void append_error(grpc_error **composite, grpc_error *error,
275
274
  threads that woke up MUST NOT call grpc_wakeup_fd_consume_wakeup() */
276
275
  static grpc_wakeup_fd polling_island_wakeup_fd;
277
276
 
278
- /* Polling island freelist */
279
- static gpr_mu g_pi_freelist_mu;
280
- static polling_island *g_pi_freelist = NULL;
281
-
282
- static void polling_island_delete(); /* Forward declaration */
277
+ /* Forward declaration */
278
+ static void polling_island_delete(grpc_exec_ctx *exec_ctx, polling_island *pi);
283
279
 
284
280
  #ifdef GRPC_TSAN
285
281
  /* Currently TSAN may incorrectly flag data races between epoll_ctl and
@@ -293,28 +289,35 @@ gpr_atm g_epoll_sync;
293
289
  #endif /* defined(GRPC_TSAN) */
294
290
 
295
291
  #ifdef GRPC_PI_REF_COUNT_DEBUG
296
- void pi_add_ref(polling_island *pi);
297
- void pi_unref(polling_island *pi);
292
+ static void pi_add_ref(polling_island *pi);
293
+ static void pi_unref(grpc_exec_ctx *exec_ctx, polling_island *pi);
298
294
 
299
- void pi_add_ref_dbg(polling_island *pi, char *reason, char *file, int line) {
300
- long old_cnt = gpr_atm_acq_load(&(pi->ref_count.count));
295
+ static void pi_add_ref_dbg(polling_island *pi, char *reason, char *file,
296
+ int line) {
297
+ long old_cnt = gpr_atm_acq_load(&pi->ref_count);
301
298
  pi_add_ref(pi);
302
299
  gpr_log(GPR_DEBUG, "Add ref pi: %p, old: %ld -> new:%ld (%s) - (%s, %d)",
303
300
  (void *)pi, old_cnt, old_cnt + 1, reason, file, line);
304
301
  }
305
302
 
306
- void pi_unref_dbg(polling_island *pi, char *reason, char *file, int line) {
307
- long old_cnt = gpr_atm_acq_load(&(pi->ref_count.count));
308
- pi_unref(pi);
303
+ static void pi_unref_dbg(grpc_exec_ctx *exec_ctx, polling_island *pi,
304
+ char *reason, char *file, int line) {
305
+ long old_cnt = gpr_atm_acq_load(&pi->ref_count);
306
+ pi_unref(exec_ctx, pi);
309
307
  gpr_log(GPR_DEBUG, "Unref pi: %p, old:%ld -> new:%ld (%s) - (%s, %d)",
310
308
  (void *)pi, old_cnt, (old_cnt - 1), reason, file, line);
311
309
  }
312
310
  #endif
313
311
 
314
- void pi_add_ref(polling_island *pi) { gpr_ref(&pi->ref_count); }
312
+ static void pi_add_ref(polling_island *pi) {
313
+ gpr_atm_no_barrier_fetch_add(&pi->ref_count, 1);
314
+ }
315
315
 
316
- void pi_unref(polling_island *pi) {
317
- /* If ref count went to zero, delete the polling island.
316
+ static void pi_unref(grpc_exec_ctx *exec_ctx, polling_island *pi) {
317
+ /* If ref count went to one, we're back to just the workqueue owning a ref.
318
+ Unref the workqueue to break the loop.
319
+
320
+ If ref count went to zero, delete the polling island.
318
321
  Note that this deletion not be done under a lock. Once the ref count goes
319
322
  to zero, we are guaranteed that no one else holds a reference to the
320
323
  polling island (and that there is no racing pi_add_ref() call either).
@@ -322,12 +325,20 @@ void pi_unref(polling_island *pi) {
322
325
  Also, if we are deleting the polling island and the merged_to field is
323
326
  non-empty, we should remove a ref to the merged_to polling island
324
327
  */
325
- if (gpr_unref(&pi->ref_count)) {
326
- polling_island *next = (polling_island *)gpr_atm_acq_load(&pi->merged_to);
327
- polling_island_delete(pi);
328
- if (next != NULL) {
329
- PI_UNREF(next, "pi_delete"); /* Recursive call */
328
+ switch (gpr_atm_full_fetch_add(&pi->ref_count, -1)) {
329
+ case 2: /* last external ref: the only one now owned is by the workqueue */
330
+ GRPC_WORKQUEUE_UNREF(exec_ctx, pi->workqueue, "polling_island");
331
+ break;
332
+ case 1: {
333
+ polling_island *next = (polling_island *)gpr_atm_acq_load(&pi->merged_to);
334
+ polling_island_delete(exec_ctx, pi);
335
+ if (next != NULL) {
336
+ PI_UNREF(exec_ctx, next, "pi_delete"); /* Recursive call */
337
+ }
338
+ break;
330
339
  }
340
+ case 0:
341
+ GPR_UNREACHABLE_CODE(return );
331
342
  }
332
343
  }
333
344
 
@@ -462,69 +473,68 @@ static void polling_island_remove_fd_locked(polling_island *pi, grpc_fd *fd,
462
473
  }
463
474
 
464
475
  /* Might return NULL in case of an error */
465
- static polling_island *polling_island_create(grpc_fd *initial_fd,
476
+ static polling_island *polling_island_create(grpc_exec_ctx *exec_ctx,
477
+ grpc_fd *initial_fd,
466
478
  grpc_error **error) {
467
479
  polling_island *pi = NULL;
468
- char *err_msg;
469
480
  const char *err_desc = "polling_island_create";
470
481
 
471
- /* Try to get one from the polling island freelist */
472
- gpr_mu_lock(&g_pi_freelist_mu);
473
- if (g_pi_freelist != NULL) {
474
- pi = g_pi_freelist;
475
- g_pi_freelist = g_pi_freelist->next_free;
476
- pi->next_free = NULL;
477
- }
478
- gpr_mu_unlock(&g_pi_freelist_mu);
482
+ *error = GRPC_ERROR_NONE;
479
483
 
480
- /* Create new polling island if we could not get one from the free list */
481
- if (pi == NULL) {
482
- pi = gpr_malloc(sizeof(*pi));
483
- gpr_mu_init(&pi->mu);
484
- pi->fd_cnt = 0;
485
- pi->fd_capacity = 0;
486
- pi->fds = NULL;
487
- }
484
+ pi = gpr_malloc(sizeof(*pi));
485
+ gpr_mu_init(&pi->mu);
486
+ pi->fd_cnt = 0;
487
+ pi->fd_capacity = 0;
488
+ pi->fds = NULL;
489
+ pi->epoll_fd = -1;
490
+ pi->workqueue = NULL;
488
491
 
489
- gpr_ref_init(&pi->ref_count, 0);
492
+ gpr_atm_rel_store(&pi->ref_count, 0);
490
493
  gpr_atm_rel_store(&pi->merged_to, (gpr_atm)NULL);
491
494
 
492
495
  pi->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
493
496
 
494
497
  if (pi->epoll_fd < 0) {
495
- gpr_asprintf(&err_msg, "epoll_create1 failed with error %d (%s)", errno,
496
- strerror(errno));
497
- append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc);
498
- gpr_free(err_msg);
499
- } else {
500
- polling_island_add_wakeup_fd_locked(pi, &grpc_global_wakeup_fd, error);
501
- pi->next_free = NULL;
498
+ append_error(error, GRPC_OS_ERROR(errno, "epoll_create1"), err_desc);
499
+ goto done;
500
+ }
502
501
 
503
- if (initial_fd != NULL) {
504
- /* Lock the polling island here just in case we got this structure from
505
- the freelist and the polling island lock was not released yet (by the
506
- code that adds the polling island to the freelist) */
507
- gpr_mu_lock(&pi->mu);
508
- polling_island_add_fds_locked(pi, &initial_fd, 1, true, error);
509
- gpr_mu_unlock(&pi->mu);
510
- }
502
+ polling_island_add_wakeup_fd_locked(pi, &grpc_global_wakeup_fd, error);
503
+
504
+ if (initial_fd != NULL) {
505
+ polling_island_add_fds_locked(pi, &initial_fd, 1, true, error);
506
+ }
507
+
508
+ if (append_error(error, grpc_workqueue_create(exec_ctx, &pi->workqueue),
509
+ err_desc) &&
510
+ *error == GRPC_ERROR_NONE) {
511
+ polling_island_add_fds_locked(pi, &pi->workqueue->wakeup_read_fd, 1, true,
512
+ error);
513
+ GPR_ASSERT(pi->workqueue->wakeup_read_fd->polling_island == NULL);
514
+ pi->workqueue->wakeup_read_fd->polling_island = pi;
515
+ PI_ADD_REF(pi, "fd");
511
516
  }
512
517
 
518
+ done:
519
+ if (*error != GRPC_ERROR_NONE) {
520
+ if (pi->workqueue != NULL) {
521
+ GRPC_WORKQUEUE_UNREF(exec_ctx, pi->workqueue, "polling_island");
522
+ }
523
+ polling_island_delete(exec_ctx, pi);
524
+ pi = NULL;
525
+ }
513
526
  return pi;
514
527
  }
515
528
 
516
- static void polling_island_delete(polling_island *pi) {
529
+ static void polling_island_delete(grpc_exec_ctx *exec_ctx, polling_island *pi) {
517
530
  GPR_ASSERT(pi->fd_cnt == 0);
518
531
 
519
- gpr_atm_rel_store(&pi->merged_to, (gpr_atm)NULL);
520
-
521
- close(pi->epoll_fd);
522
- pi->epoll_fd = -1;
523
-
524
- gpr_mu_lock(&g_pi_freelist_mu);
525
- pi->next_free = g_pi_freelist;
526
- g_pi_freelist = pi;
527
- gpr_mu_unlock(&g_pi_freelist_mu);
532
+ if (pi->epoll_fd >= 0) {
533
+ close(pi->epoll_fd);
534
+ }
535
+ gpr_mu_destroy(&pi->mu);
536
+ gpr_free(pi->fds);
537
+ gpr_free(pi);
528
538
  }
529
539
 
530
540
  /* Attempts to gets the last polling island in the linked list (liked by the
@@ -704,9 +714,6 @@ static polling_island *polling_island_merge(polling_island *p,
704
714
  static grpc_error *polling_island_global_init() {
705
715
  grpc_error *error = GRPC_ERROR_NONE;
706
716
 
707
- gpr_mu_init(&g_pi_freelist_mu);
708
- g_pi_freelist = NULL;
709
-
710
717
  error = grpc_wakeup_fd_init(&polling_island_wakeup_fd);
711
718
  if (error == GRPC_ERROR_NONE) {
712
719
  error = grpc_wakeup_fd_wakeup(&polling_island_wakeup_fd);
@@ -716,18 +723,6 @@ static grpc_error *polling_island_global_init() {
716
723
  }
717
724
 
718
725
  static void polling_island_global_shutdown() {
719
- polling_island *next;
720
- gpr_mu_lock(&g_pi_freelist_mu);
721
- gpr_mu_unlock(&g_pi_freelist_mu);
722
- while (g_pi_freelist != NULL) {
723
- next = g_pi_freelist->next_free;
724
- gpr_mu_destroy(&g_pi_freelist->mu);
725
- gpr_free(g_pi_freelist->fds);
726
- gpr_free(g_pi_freelist);
727
- g_pi_freelist = next;
728
- }
729
- gpr_mu_destroy(&g_pi_freelist_mu);
730
-
731
726
  grpc_wakeup_fd_destroy(&polling_island_wakeup_fd);
732
727
  }
733
728
 
@@ -845,7 +840,6 @@ static grpc_fd *fd_create(int fd, const char *name) {
845
840
  if (new_fd == NULL) {
846
841
  new_fd = gpr_malloc(sizeof(grpc_fd));
847
842
  gpr_mu_init(&new_fd->mu);
848
- gpr_mu_init(&new_fd->pi_mu);
849
843
  }
850
844
 
851
845
  /* Note: It is not really needed to get the new_fd->mu lock here. If this is a
@@ -896,6 +890,7 @@ static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
896
890
  const char *reason) {
897
891
  bool is_fd_closed = false;
898
892
  grpc_error *error = GRPC_ERROR_NONE;
893
+ polling_island *unref_pi = NULL;
899
894
 
900
895
  gpr_mu_lock(&fd->mu);
901
896
  fd->on_done_closure = on_done;
@@ -923,21 +918,26 @@ static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
923
918
  - Unlock the latest polling island
924
919
  - Set fd->polling_island to NULL (but remove the ref on the polling island
925
920
  before doing this.) */
926
- gpr_mu_lock(&fd->pi_mu);
927
921
  if (fd->polling_island != NULL) {
928
922
  polling_island *pi_latest = polling_island_lock(fd->polling_island);
929
923
  polling_island_remove_fd_locked(pi_latest, fd, is_fd_closed, &error);
930
924
  gpr_mu_unlock(&pi_latest->mu);
931
925
 
932
- PI_UNREF(fd->polling_island, "fd_orphan");
926
+ unref_pi = fd->polling_island;
933
927
  fd->polling_island = NULL;
934
928
  }
935
- gpr_mu_unlock(&fd->pi_mu);
936
929
 
937
930
  grpc_exec_ctx_sched(exec_ctx, fd->on_done_closure, error, NULL);
938
931
 
939
932
  gpr_mu_unlock(&fd->mu);
940
933
  UNREF_BY(fd, 2, reason); /* Drop the reference */
934
+ if (unref_pi != NULL) {
935
+ /* Unref stale polling island here, outside the fd lock above.
936
+ The polling island owns a workqueue which owns an fd, and unreffing
937
+ inside the lock can cause an eventual lock loop that makes TSAN very
938
+ unhappy. */
939
+ PI_UNREF(exec_ctx, unref_pi, "fd_orphan");
940
+ }
941
941
  GRPC_LOG_IF_ERROR("fd_orphan", GRPC_ERROR_REF(error));
942
942
  }
943
943
 
@@ -1037,6 +1037,17 @@ static void fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
1037
1037
  gpr_mu_unlock(&fd->mu);
1038
1038
  }
1039
1039
 
1040
+ static grpc_workqueue *fd_get_workqueue(grpc_fd *fd) {
1041
+ gpr_mu_lock(&fd->mu);
1042
+ grpc_workqueue *workqueue = NULL;
1043
+ if (fd->polling_island != NULL) {
1044
+ workqueue =
1045
+ GRPC_WORKQUEUE_REF(fd->polling_island->workqueue, "get_workqueue");
1046
+ }
1047
+ gpr_mu_unlock(&fd->mu);
1048
+ return workqueue;
1049
+ }
1050
+
1040
1051
  /*******************************************************************************
1041
1052
  * Pollset Definitions
1042
1053
  */
@@ -1227,9 +1238,10 @@ static void fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
1227
1238
  gpr_mu_unlock(&fd->mu);
1228
1239
  }
1229
1240
 
1230
- static void pollset_release_polling_island(grpc_pollset *ps, char *reason) {
1241
+ static void pollset_release_polling_island(grpc_exec_ctx *exec_ctx,
1242
+ grpc_pollset *ps, char *reason) {
1231
1243
  if (ps->polling_island != NULL) {
1232
- PI_UNREF(ps->polling_island, reason);
1244
+ PI_UNREF(exec_ctx, ps->polling_island, reason);
1233
1245
  }
1234
1246
  ps->polling_island = NULL;
1235
1247
  }
@@ -1242,7 +1254,7 @@ static void finish_shutdown_locked(grpc_exec_ctx *exec_ctx,
1242
1254
  pollset->finish_shutdown_called = true;
1243
1255
 
1244
1256
  /* Release the ref and set pollset->polling_island to NULL */
1245
- pollset_release_polling_island(pollset, "ps_shutdown");
1257
+ pollset_release_polling_island(exec_ctx, pollset, "ps_shutdown");
1246
1258
  grpc_exec_ctx_sched(exec_ctx, pollset->shutdown_done, GRPC_ERROR_NONE, NULL);
1247
1259
  }
1248
1260
 
@@ -1281,7 +1293,7 @@ static void pollset_reset(grpc_pollset *pollset) {
1281
1293
  pollset->finish_shutdown_called = false;
1282
1294
  pollset->kicked_without_pollers = false;
1283
1295
  pollset->shutdown_done = NULL;
1284
- pollset_release_polling_island(pollset, "ps_reset");
1296
+ GPR_ASSERT(pollset->polling_island == NULL);
1285
1297
  }
1286
1298
 
1287
1299
  #define GRPC_EPOLL_MAX_EVENTS 1000
@@ -1309,7 +1321,7 @@ static void pollset_work_and_unlock(grpc_exec_ctx *exec_ctx,
1309
1321
  this function (i.e pollset_work_and_unlock()) is called */
1310
1322
 
1311
1323
  if (pollset->polling_island == NULL) {
1312
- pollset->polling_island = polling_island_create(NULL, error);
1324
+ pollset->polling_island = polling_island_create(exec_ctx, NULL, error);
1313
1325
  if (pollset->polling_island == NULL) {
1314
1326
  GPR_TIMER_END("pollset_work_and_unlock", 0);
1315
1327
  return; /* Fatal error. We cannot continue */
@@ -1329,7 +1341,7 @@ static void pollset_work_and_unlock(grpc_exec_ctx *exec_ctx,
1329
1341
  /* Always do PI_ADD_REF before PI_UNREF because PI_UNREF may cause the
1330
1342
  polling island to be deleted */
1331
1343
  PI_ADD_REF(pi, "ps");
1332
- PI_UNREF(pollset->polling_island, "ps");
1344
+ PI_UNREF(exec_ctx, pollset->polling_island, "ps");
1333
1345
  pollset->polling_island = pi;
1334
1346
  }
1335
1347
 
@@ -1400,7 +1412,7 @@ static void pollset_work_and_unlock(grpc_exec_ctx *exec_ctx,
1400
1412
  that we got before releasing the polling island lock). This is because
1401
1413
  pollset->polling_island pointer might get udpated in other parts of the
1402
1414
  code when there is an island merge while we are doing epoll_wait() above */
1403
- PI_UNREF(pi, "ps_work");
1415
+ PI_UNREF(exec_ctx, pi, "ps_work");
1404
1416
 
1405
1417
  GPR_TIMER_END("pollset_work_and_unlock", 0);
1406
1418
  }
@@ -1517,10 +1529,11 @@ static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
1517
1529
  grpc_error *error = GRPC_ERROR_NONE;
1518
1530
 
1519
1531
  gpr_mu_lock(&pollset->mu);
1520
- gpr_mu_lock(&fd->pi_mu);
1532
+ gpr_mu_lock(&fd->mu);
1521
1533
 
1522
1534
  polling_island *pi_new = NULL;
1523
1535
 
1536
+ retry:
1524
1537
  /* 1) If fd->polling_island and pollset->polling_island are both non-NULL and
1525
1538
  * equal, do nothing.
1526
1539
  * 2) If fd->polling_island and pollset->polling_island are both NULL, create
@@ -1535,15 +1548,44 @@ static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
1535
1548
  * polling_island fields in both fd and pollset to point to the merged
1536
1549
  * polling island.
1537
1550
  */
1551
+
1552
+ if (fd->orphaned) {
1553
+ gpr_mu_unlock(&fd->mu);
1554
+ gpr_mu_unlock(&pollset->mu);
1555
+ /* early out */
1556
+ return;
1557
+ }
1558
+
1538
1559
  if (fd->polling_island == pollset->polling_island) {
1539
1560
  pi_new = fd->polling_island;
1540
1561
  if (pi_new == NULL) {
1541
- pi_new = polling_island_create(fd, &error);
1542
-
1543
- GRPC_POLLING_TRACE(
1544
- "pollset_add_fd: Created new polling island. pi_new: %p (fd: %d, "
1545
- "pollset: %p)",
1546
- (void *)pi_new, fd->fd, (void *)pollset);
1562
+ /* Unlock before creating a new polling island: the polling island will
1563
+ create a workqueue which creates a file descriptor, and holding an fd
1564
+ lock here can eventually cause a loop to appear to TSAN (making it
1565
+ unhappy). We don't think it's a real loop (there's an epoch point where
1566
+ that loop possibility disappears), but the advantages of keeping TSAN
1567
+ happy outweigh any performance advantage we might have by keeping the
1568
+ lock held. */
1569
+ gpr_mu_unlock(&fd->mu);
1570
+ pi_new = polling_island_create(exec_ctx, fd, &error);
1571
+ gpr_mu_lock(&fd->mu);
1572
+ /* Need to reverify any assumptions made between the initial lock and
1573
+ getting to this branch: if they've changed, we need to throw away our
1574
+ work and figure things out again. */
1575
+ if (fd->polling_island != NULL) {
1576
+ GRPC_POLLING_TRACE(
1577
+ "pollset_add_fd: Raced creating new polling island. pi_new: %p "
1578
+ "(fd: %d, pollset: %p)",
1579
+ (void *)pi_new, fd->fd, (void *)pollset);
1580
+ PI_ADD_REF(pi_new, "dance_of_destruction");
1581
+ PI_UNREF(exec_ctx, pi_new, "dance_of_destruction");
1582
+ goto retry;
1583
+ } else {
1584
+ GRPC_POLLING_TRACE(
1585
+ "pollset_add_fd: Created new polling island. pi_new: %p (fd: %d, "
1586
+ "pollset: %p)",
1587
+ (void *)pi_new, fd->fd, (void *)pollset);
1588
+ }
1547
1589
  }
1548
1590
  } else if (fd->polling_island == NULL) {
1549
1591
  pi_new = polling_island_lock(pollset->polling_island);
@@ -1579,7 +1621,7 @@ static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
1579
1621
  if (fd->polling_island != pi_new) {
1580
1622
  PI_ADD_REF(pi_new, "fd");
1581
1623
  if (fd->polling_island != NULL) {
1582
- PI_UNREF(fd->polling_island, "fd");
1624
+ PI_UNREF(exec_ctx, fd->polling_island, "fd");
1583
1625
  }
1584
1626
  fd->polling_island = pi_new;
1585
1627
  }
@@ -1587,13 +1629,15 @@ static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
1587
1629
  if (pollset->polling_island != pi_new) {
1588
1630
  PI_ADD_REF(pi_new, "ps");
1589
1631
  if (pollset->polling_island != NULL) {
1590
- PI_UNREF(pollset->polling_island, "ps");
1632
+ PI_UNREF(exec_ctx, pollset->polling_island, "ps");
1591
1633
  }
1592
1634
  pollset->polling_island = pi_new;
1593
1635
  }
1594
1636
 
1595
- gpr_mu_unlock(&fd->pi_mu);
1637
+ gpr_mu_unlock(&fd->mu);
1596
1638
  gpr_mu_unlock(&pollset->mu);
1639
+
1640
+ GRPC_LOG_IF_ERROR("pollset_add_fd", error);
1597
1641
  }
1598
1642
 
1599
1643
  /*******************************************************************************
@@ -1744,9 +1788,9 @@ static void pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx,
1744
1788
  void *grpc_fd_get_polling_island(grpc_fd *fd) {
1745
1789
  polling_island *pi;
1746
1790
 
1747
- gpr_mu_lock(&fd->pi_mu);
1791
+ gpr_mu_lock(&fd->mu);
1748
1792
  pi = fd->polling_island;
1749
- gpr_mu_unlock(&fd->pi_mu);
1793
+ gpr_mu_unlock(&fd->mu);
1750
1794
 
1751
1795
  return pi;
1752
1796
  }
@@ -1794,6 +1838,7 @@ static const grpc_event_engine_vtable vtable = {
1794
1838
  .fd_notify_on_read = fd_notify_on_read,
1795
1839
  .fd_notify_on_write = fd_notify_on_write,
1796
1840
  .fd_get_read_notifier_pollset = fd_get_read_notifier_pollset,
1841
+ .fd_get_workqueue = fd_get_workqueue,
1797
1842
 
1798
1843
  .pollset_init = pollset_init,
1799
1844
  .pollset_shutdown = pollset_shutdown,